Как "уронить" сборщик мусора?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 12.11.04 05:57
Оценка: 3 (1)
Слышал, что можно как-то хитрым образом написать программу так, что сборщик мусора уйдет в глубокий даун разгребая мусор, короче будет работать неэффективно. Правда это или миф? Если у кого есть конкретные примеры таких программ — поделитесь, пожалуйста.


В свою очередь, попробовал испытать пронырливость сборщика мусора. Рассуждал так: чем больше ссылок между объектами — тем хуже для сборщика мусора. Если у нас есть N штук объектов, то максимально возможное количество ссылок между ними равно N^2 — это когда все объекты друг на друга ссылаются (включая ссылки на себя). То есть случай N^2 ссылок является самым сложным для сборщика мусора, так или не так?

Создаю N объектов, устанавливаю между ними N^2 связей, потом натравливаю на эту структуру сборщик мусора и измеряю время. Вот что наизмерял:
N =  1000, new  50   ms, GC  70   ms
N =  2000, new  230  ms, GC  261  ms
N =  3000, new  511  ms, GC  570  ms
N =  4000, new  912  ms, GC  1011 ms
N =  5000, new  1452 ms, GC  1773 ms
N =  6000, new  2083 ms, GC  2333 ms
N =  7000, new  5208 ms, GC  3995 ms
N =  8000, new  5138 ms, GC  4907 ms

В этой таблице, время "new" включает в себя время на создание N объектов и время на установление между ними N^2 связей, время "GC" включает в себя полную очистку памяти сборщиком мусора и подготовки ее к повторному использованию.

Вывод. Сборщик мусора работает примерно столько же времени сколько времени требуется на само создание данной структуры в памяти, причем на малом количестве малых объектов он чуть отстает, а на большом количестве больших объектов он даже работает шустрее.

Я что-то не так померил или сборщик мусора действительно крут?


Исходный код программы:

MODULE TestGC;

IMPORT StdLog, Services;
    
PROCEDURE f(N: INTEGER);
TYPE Objects = POINTER TO ARRAY OF Object;
     Object  = POINTER TO RECORD ref: Objects END;
VAR obj: Objects; i,j,n: INTEGER; t: LONGINT;
BEGIN
  StdLog.String("N = "); StdLog.Int(N);

  (* Создание объектов *)
  t := Services.Ticks();
    NEW(obj, N);
    FOR i := 0 TO N-1 DO NEW(obj[i]) END;
    FOR i := 0 TO N-1 DO 
      NEW(obj[i].ref, N);
      FOR j := 0 TO N-1 DO obj[i].ref[j] := obj[j] END
    END;
  t := Services.Ticks() - t;
  StdLog.String(", new "); StdLog.Int(t); StdLog.String(" ms");

  (* Удаление объектов *)
  t := Services.Ticks();    
    obj := NIL;
    Services.Collect();
  t := Services.Ticks() - t;
  StdLog.String(", GC "); StdLog.Int(t); 
  StdLog.String(" ms");StdLog.Ln();
END f;

PROCEDURE Test* ();
VAR n: INTEGER;
BEGIN
  StdLog.Ln();
  FOR n := 1 TO 8 DO f(n*1000) END
END Test; 
    
END TestGC.

Размер одного объекта = 4*N + const, где const — это то что хранит в себе RTTI информацию.

Машина: процессор Celeron 1100 Coppermain 128Kb, память 448Mb PC100.
Re: Как "уронить" сборщик мусора?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 12.11.04 06:00
Оценка:
P. S.
Забыл написать, что пользовался компилятором BlackBox 1.4
Re: Как "уронить" сборщик мусора?
От: Трурль  
Дата: 12.11.04 06:41
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ> Рассуждал так: чем больше ссылок между объектами — тем хуже для сборщика мусора.

Это неверно.
Re: Как "уронить" сборщик мусора?
От: xvost Германия http://www.jetbrains.com/company/people/Pasynkov_Eugene.html
Дата: 12.11.04 06:42
Оценка: +1
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Я что-то не так померил или сборщик мусора действительно крут?


Перед удалением объектов вызови GC.Collect еще раз пока объекты не могут быть удалены. Для того чтобы они перешли в следующее поколение. И опубликуй плиз результаты. Они могут сильно отличаться
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Re: Как "уронить" сборщик мусора?
От: alexeiz  
Дата: 12.11.04 08:00
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Создаю N объектов, устанавливаю между ними N^2 связей, потом натравливаю на эту структуру сборщик мусора и измеряю время. Вот что наизмерял:

СГ>
СГ>N =  8000, new  5138 ms, GC  4907 ms
СГ>

5 секунд? Время сбора мусора 5 секунд? Что-же это за GC такой?
Re[2]: Как "уронить" сборщик мусора?
От: xvost Германия http://www.jetbrains.com/company/people/Pasynkov_Eugene.html
Дата: 12.11.04 08:14
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>5 секунд? Время сбора мусора 5 секунд? Что-же это за GC такой?


Все нормально. 8 тыс объектов, 16 млн связей — результат предсказуем.

Кстати, для .NET я вообще знаю способы заставить GC лечь намертво. Способы тривиальные.
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Re[3]: Как "уронить" сборщик мусора?
От: alexeiz  
Дата: 12.11.04 08:28
Оценка:
Здравствуйте, xvost, Вы писали:

X>Здравствуйте, alexeiz, Вы писали:


A>>5 секунд? Время сбора мусора 5 секунд? Что-же это за GC такой?


X>Все нормально. 8 тыс объектов, 16 млн связей — результат предсказуем.


X>Кстати, для .NET я вообще знаю способы заставить GC лечь намертво. Способы тривиальные.


Такой примерчик .NET GC соберет за >1ms. Он не будет подсчитывать ссылки в недоступных объектах. Кстати, "способы заставить .NET GC лечь намертво" — в студию.
Re[4]: Как "уронить" сборщик мусора?
От: xvost Германия http://www.jetbrains.com/company/people/Pasynkov_Eugene.html
Дата: 12.11.04 08:44
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Такой примерчик .NET GC соберет за >1ms.

A>Он не будет подсчитывать ссылки в недоступных объектах.

Это так. Но если ты создашь 2 такие независимые струкуры, и попробуешь одну из них удалить — GC будет несколько секунд обегать имеющиеся объекты

A>Кстати, "способы заставить .NET GC лечь намертво" — в студию.


Лови.

class C
{
  public C() {}
  ~C() {System.Threading.Thread.Sleep(1000000);}

  public static void Main()
  {
    C c = new C();

    System.GC.Collect();
    System.GC.WaitForPendingFinalizers();
  }
}


Вызов System.GC.WaitForPendingFinalizers() вставлен только для того, чтобы в заставить отработать деструктор прямо сейчас. В реальной жизни этот вызов ненужен — рано или поздно деструктор запустится.

При этом основная неприятность всего этого — во время GC .NET полностью блокирует все потоки приложения. Т.е. имеем "мертвый вис".
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Re[5]: Как "уронить" сборщик мусора?
От: alexeiz  
Дата: 12.11.04 08:47
Оценка:
Здравствуйте, xvost, Вы писали:

X>Здравствуйте, alexeiz, Вы писали:


A>>Такой примерчик .NET GC соберет за >1ms.

A>>Он не будет подсчитывать ссылки в недоступных объектах.

X>Это так. Но если ты создашь 2 такие независимые струкуры, и попробуешь одну из них удалить — GC будет несколько секунд обегать имеющиеся объекты


Докажи.

A>>Кстати, "способы заставить .NET GC лечь намертво" — в студию.


X>Лови.


...

X>Вызов System.GC.WaitForPendingFinalizers() вставлен только для того, чтобы в заставить отработать деструктор прямо сейчас. В реальной жизни этот вызов ненужен — рано или поздно деструктор запустится.


X>При этом основная неприятность всего этого — во время GC .NET полностью блокирует все потоки приложения. Т.е. имеем "мертвый вис".


Такой "способ" я не приму. Я думал, что ты знаешь честный способ.
Re[5]: Как "уронить" сборщик мусора?
От: Воронков Василий Россия  
Дата: 12.11.04 08:52
Оценка: +1
Здравствуйте, xvost, Вы писали:

X>
X>class C
X>{
X>  public C() {}
X>  ~C() {System.Threading.Thread.Sleep(1000000);}

X>  public static void Main()
X>  {
X>    C c = new C();

X>    System.GC.Collect();
X>    System.GC.WaitForPendingFinalizers();
X>  }
X>}
X>


Это из области:

static void Main()
{
  for(;;) { }
}
Re[6]: Как "уронить" сборщик мусора?
От: xvost Германия http://www.jetbrains.com/company/people/Pasynkov_Eugene.html
Дата: 12.11.04 08:56
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>
ВВ>static void Main()
ВВ>{
ВВ>  for(;;) { }
ВВ>}
ВВ>


НЕТ!

И вот почему:

Твой пример — блокируется только тред содержащий цикл. Т.е. например остальные потоки сервера спокойно продолжают обслуживать своих клиентов. В моем примере — нафиг блокируется ВЕСЬ сервер целиком.
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Re[5]: Как "уронить" сборщик мусора?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.11.04 09:03
Оценка:
Здравствуйте, xvost, Вы писали:

X>При этом основная неприятность всего этого — во время GC .NET полностью блокирует все потоки приложения. Т.е. имеем "мертвый вис".


А вот здесь ошибка — финалайзеры, в отличие от собственно сканирования графов и реструктуризации кучи, работают в отдельном потоке.
... << RSDN@Home 1.1.4 beta 3 rev. 230>>
AVK Blog
Re[6]: Как "уронить" сборщик мусора?
От: xvost Германия http://www.jetbrains.com/company/people/Pasynkov_Eugene.html
Дата: 12.11.04 09:16
Оценка: :))
Здравствуйте, AndrewVK, Вы писали:

AVK>А вот здесь ошибка — финалайзеры, в отличие от собственно сканирования графов и реструктуризации кучи, работают в отдельном потоке.


Oops! Проверил — я был неправ.

Значит пока что я не знаю "честного" способа уронить GC
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Re[2]: А как измерить скорость сборки мусора?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 12.11.04 09:20
Оценка:
Отвечаю сразу на 2 сообщения:

Здравствуйте, alexeiz, Вы писали:

СГ>>Создаю N объектов, устанавливаю между ними N^2 связей, потом натравливаю на эту структуру сборщик мусора и измеряю время. Вот что наизмерял:

СГ>>
СГ>>N =  8000, new  5138 ms, GC  4907 ms
СГ>>

A>5 секунд? Время сбора мусора 5 секунд? Что-же это за GC такой?

Здравствуйте, xvost, Вы писали:

X>Перед удалением объектов вызови GC.Collect еще раз пока объекты не могут быть удалены. Для того чтобы они перешли в следующее поколение. И опубликуй плиз результаты. Они могут сильно отличаться


Знаете, сейчас продолжил издевательства над BlackBox-совским GC и пришел к заключению, что вызов Services.Collect() для него ровным счетом ничего не означает (Даже не смотря на то, что выполняется много времени). Чем реально занимается этот Services.Collect(), ума не приложу , хотя в хелпе черным по белому написано: "Forces a garbage collection". Реальная чистка памяти, как я понял, возникает только тогда когда сам BlackBox этого захочет, а раз так, то у меня нет способа измерить реальную скорость сборки мусора в BlackBox. Вот такие пироги............ Я могу измерить только суммарную скорость операций "создание+удаление".


Вот, например, создание/удаление (в цикле 10 раз) N = 5000 объектов с N^2 ссылками друг на друга, на машине Athlon 1.47Ghz 256Mb DDR266 отнимает от 811 до 820 тиков.
MODULE TestGC;

IMPORT StdLog, Services;

PROCEDURE f(N: INTEGER);
TYPE Objects = POINTER TO ARRAY OF Object;
     Object  = POINTER TO RECORD ref: Objects END;
VAR obj: Objects; i,j: INTEGER;
BEGIN
  NEW(obj, N);
  FOR i := 0 TO N-1 DO NEW(obj[i]) END;
  FOR i := 0 TO N-1 DO 
    NEW(obj[i].ref, N);
    FOR j := 0 TO N-1 DO obj[i].ref[j] := obj[j] END
  END
END f;

PROCEDURE Test* ();
CONST N = 5000;
VAR n: INTEGER; t: LONGINT;
BEGIN
  t := Services.Ticks();
  FOR n := 1 TO 10 DO f(N) END;
  t := Services.Ticks() - t;
  StdLog.String("N ="); StdLog.Int(N);
  StdLog.String(", t ="); StdLog.Int(t DIV 10); StdLog.String(" ms");
  StdLog.Ln();
END Test; 
    
END TestGC.


Log:

N = 5000, t = 811 ms


Но сколько именно из этой 0.8 секунды тратится на создание такой сложной структуры в памяти, а сколько тратится на ее уничтожение — я не знаю. В сумме 0.8 секунды и точка.
Re[7]: Как "уронить" сборщик мусора?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.11.04 09:35
Оценка:
Здравствуйте, xvost, Вы писали:

X>Oops! Проверил — я был неправ.


X>Значит пока что я не знаю "честного" способа уронить GC


Что значит честный? Вот такой код собственно в свое время через продолжительное время убивал януса:
public sealed class SomeSingleton
{
    private SomeSingleton() {}
    
    public readonly SomeSingleton Instance = new SomeSingleton();
    
    public event EventHandler SomeEvent;
}

...

private void RefreshForums
{
    _forums.Clear();
    foreach (ForumData fd in GetFromDb())
        _forums.Add(new Forum(fd));
}

...

public class Forum
{
    public Forum(ForumData fd)
    {
        //...
        SomeSingleton.SomeEvent += new EventHandler(SomeEventFired);
    }
    
    //...
}
... << RSDN@Home 1.1.4 beta 3 rev. 230>>
AVK Blog
Re[2]: Как "уронить" сборщик мусора?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 12.11.04 12:29
Оценка:
Здравствуйте, Трурль, Вы писали:

Т>Здравствуйте, Сергей Губанов, Вы писали:


СГ>> Рассуждал так: чем больше ссылок между объектами — тем хуже для сборщика мусора.

Т>Это неверно.

А как верно?
Re[5]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.11.04 17:43
Оценка:
Здравствуйте, xvost, Вы писали:

X>Лови.


X>
X>class C
X>{
X>  public C() {}
X>  ~C() {System.Threading.Thread.Sleep(1000000);}

X>  public static void Main()
X>  {
X>    C c = new C();

X>    System.GC.Collect();
X>    System.GC.WaitForPendingFinalizers();
X>  }
X>}
X>


Ты его хоть запускал?

X>Вызов System.GC.WaitForPendingFinalizers() вставлен только для того, чтобы в заставить отработать деструктор прямо сейчас. В реальной жизни этот вызов ненужен — рано или поздно деструктор запустится.


Трепачь находка для шпионов. Если ЖЦ видет что финалайзер занят более чем на определенное время, то плюет на финализацию и продолжает работу.

X>При этом основная неприятность всего этого — во время GC .NET полностью блокирует все потоки приложения. Т.е. имеем "мертвый вис".


Кончай нести фигню и пойди почитай Рихтера.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.11.04 17:43
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Это из области:


ВВ>
ВВ>static void Main()
ВВ>{
ВВ>  for(;;) { }
ВВ>}
ВВ>


Не это из другой области. Запусти пример и увидишь что проблем не возникнет. Так что это из области трепачей.

Ну, а завалить ЖЦ действительно не трудно. Достаточно просто не освобождать ссылки. Что с успехом продемонстрировал Синклер. Как говорится:
ArrayList _garbage = new ArrayList(); // складывать мусор тут :)
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.11.04 17:43
Оценка:
Здравствуйте, xvost, Вы писали:

X>Твой пример — блокируется только тред содержащий цикл. Т.е. например остальные потоки сервера спокойно продолжают обслуживать своих клиентов. В моем примере — нафиг блокируется ВЕСЬ сервер целиком.


1. Не ври.
2. Подними приоритет у потока и погляди как там остальные потоки спокойно...
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.11.04 17:43
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Что значит честный? Вот такой код собственно в свое время через продолжительное время убивал януса:


Это не проблемы не сборщика мусора, а проблема реализации событий. Тормоза там наступаеют не при ЖЦ, а именно при вызове событий или при привязке/отвязке.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: А как измерить скорость сборки мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.11.04 17:43
Оценка: 3 (1)
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Вот, например, создание/удаление (в цикле 10 раз) N = 5000 объектов с N^2 ссылками друг на друга, на машине Athlon 1.47Ghz 256Mb DDR266 отнимает от 811 до 820 тиков.


А чему тик равен?

СГ>
СГ>MODULE TestGC;

СГ>IMPORT StdLog, Services;

СГ>PROCEDURE f(N: INTEGER);
СГ>TYPE Objects = POINTER TO ARRAY OF Object;
СГ>     Object  = POINTER TO RECORD ref: Objects END;
СГ>VAR obj: Objects; i,j: INTEGER;
СГ>BEGIN
СГ>  NEW(obj, N);
СГ>  FOR i := 0 TO N-1 DO NEW(obj[i]) END;
СГ>  FOR i := 0 TO N-1 DO 
СГ>    NEW(obj[i].ref, N);
СГ>    FOR j := 0 TO N-1 DO obj[i].ref[j] := obj[j] END
СГ>  END
СГ>END f;

СГ>PROCEDURE Test* ();
СГ>CONST N = 5000;
СГ>VAR n: INTEGER; t: LONGINT;
СГ>BEGIN
СГ>  t := Services.Ticks();
СГ>  FOR n := 1 TO 10 DO f(N) END;
СГ>  t := Services.Ticks() - t;
СГ>  StdLog.String("N ="); StdLog.Int(N);
СГ>  StdLog.String(", t ="); StdLog.Int(t DIV 10); StdLog.String(" ms");
СГ>  StdLog.Ln();
СГ>END Test; 
    
СГ>END TestGC.
СГ>


СГ>Log:

СГ>

СГ>N = 5000, t = 811 ms


СГ>Но сколько именно из этой 0.8 секунды тратится на создание такой сложной структуры в памяти, а сколько тратится на ее уничтожение — я не знаю. В сумме 0.8 секунды и точка.



Для сравнения тоже самое на C#:
using System;

struct A
{
    public A[] Refs;
}

class Program
{
    const int Size = 5000;

    static void Main(string[] args)
    {
        PerfCounter timer = new PerfCounter();

        for (int i = 0; i < 10; i++)
        {
            timer.Start();
            f(Size);
            Console.WriteLine("Size = {0}, time = {1}", Size, timer.Finish());
        }

        Console.WriteLine("...");
        Console.ReadLine();
    }
    private static void f(int n)
    {

        A[] array = new A[n];

        for (int i = 0; i < n; i++)
            array[i] = new A();

        for (int i = 0; i < n; i++)
        {
            A a = array[i];
            a.Refs = new A[n];
            for (int j = 0; j < n; j++)
                a.Refs[j] = array[j];
        }
    }
}


На моем Атлоне 64 3500+ выдает:
Size = 5000, time = 0.1568979
Size = 5000, time = 0.1481088
Size = 5000, time = 0.148258
Size = 5000, time = 0.1483974
Size = 5000, time = 0.156944
Size = 5000, time = 0.1523546
Size = 5000, time = 0.1492008
Size = 5000, time = 0.1524101
Size = 5000, time = 0.1476894
Size = 5000, time = 0.1591912
...

Вот только к ЖЦ этот тест отношения не имеет. Это всего лишь тест на работу с указателями. Объем паяти крайне мал для частых срабатываний ЖЦ.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Как "уронить" сборщик мусора?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.11.04 19:17
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>1. Не ври.

Спокойнее. Человек мог просто ошибаться. Думаю стоит несколько ответственнее относится к тому что пишешь.
... << RSDN@Home 1.1.4 beta 3 rev. 231>>
AVK Blog
Re[9]: Как "уронить" сборщик мусора?
От: Зверёк Харьковский  
Дата: 12.11.04 20:00
Оценка: :))) :)))
Да, да, ДА, ДА! Это таки случилось!!!!
сам слушаю и вам рекомендую: 06 — We Use The Pain
FAQ — це мiй ай-кью!
Re[4]: А как измерить скорость сборки мусора?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 13.11.04 17:31
Оценка:
Здравствуйте, VladD2, Вы писали:

СГ>>Вот, например, создание/удаление (в цикле 10 раз) N = 5000 объектов с N^2 ссылками друг на друга, на машине Athlon 1.47Ghz 256Mb DDR266 отнимает от 811 до 820 тиков.


VD>А чему тик равен?


тик = 1 ms = 0.001 секунды

VD>Вот только к ЖЦ этот тест отношения не имеет. Это всего лишь тест на работу с указателями. Объем паяти крайне мал для частых срабатываний ЖЦ.


Есть N объектов, каждый объект хранит N указателей на другие объекты, размер указателя 4 байта значит нижняя оценка на используемое количество памяти:

V = 4*N^2 = 4*5000^2 = 100 Мегабайтов

Если на компе стоит 256 метров, 125 виндос себе берет, как раз остается 100 метров для программы, т.е. сборщик мусора должен срабатывать каждый раз при очередном вызове f(N).
Re[4]: А как измерить скорость сборки мусора?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 13.11.04 17:58
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>

for (int i = 0; i < 10; i++)
{
  timer.Start();
  f(Size);
  Console.WriteLine("Size = {0}, time = {1}", Size, timer.Finish());
}

VD>Вот только к ЖЦ этот тест отношения не имеет. Это всего лишь тест на работу с указателями. Объем паяти крайне мал для частых срабатываний ЖЦ.

Можно Вас попросить исправить Ваш код на следующий:
timer.Start();
for (int i = 0; i < 10; i++)
{
  f(Size);
}
Console.WriteLine("Size = {0}, time*10 = {1}", Size, timer.Finish());

А то ведь, действительно, вполне может оказаться, что скорость сборки мусора Ваш код не измеряет. Вдруг мусор чиститься как раз в то время когда идет вывод результатов в консоль, так что при следующей итерации цикла весь мусор уже очищен и измеряется всего лишь скорость создания структуры взаимоссылающихся объектов, но не время разрушения этой структуры.

Обратите внимание, мой код:
СГ>
  t := Services.Ticks();
  FOR n := 1 TO 10 DO f(N) END;
  t := Services.Ticks() - t;

как раз измерял суммарное время = "время создания структуры объектов" + "время разрушения структуры объектов".
Re: Как "уронить" сборщик мусора?
От: Lloyd Россия  
Дата: 13.11.04 18:40
Оценка: :)
Здравствуйте, Сергей Губанов, Вы писали:

Навеяло. Тему можно было бы назвать:

как завалить уборщицу
(с) Nomad

Re[4]: Сравнил скорости работы. Результаты потрясают воображ
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 13.11.04 20:51
Оценка: 3 (1)
Я немного модифицировал программы на Component Pascal и C#, после чего сравнил скорости их исполнения на моей домашней машине. Времена исполнения оказались сильно разными.

Вот исходный код программы на Component Pascal:
MODULE TestGC;

IMPORT StdLog, Services;
    
PROCEDURE f(N: INTEGER);
TYPE Objects = POINTER TO ARRAY OF Object;
     Object  = POINTER TO RECORD Refs: Objects END;
VAR X, a: Objects; i,j: INTEGER;
BEGIN
  NEW(X, N);
  FOR i := 0 TO N-1 DO NEW(X[i]) END;
  FOR i := 0 TO N-1 DO
    NEW(a, N);
    FOR j := 0 TO N-1 DO a[j] := X[j] END;
    X[i].Refs := a;
  END;
END f;

PROCEDURE Main*();
CONST N = 5000;
VAR n: INTEGER; t: LONGINT;
BEGIN
  StdLog.String("first memory allocation..."); f(N); StdLog.Ln();
  StdLog.String("start");
  t := Services.Ticks();
  FOR n := 1 TO 10 DO f(N) END;
  t := (Services.Ticks() - t) DIV 10;
  StdLog.String("t = "); StdLog.Int(t); StdLog.String(" ms");
  StdLog.Ln();
END Main;

END TestGC.

Обратите внимание на "холостой" вызов f(N); в самом начале процедуры Main. Это я сделал для того, чтобы BlackBox один раз захватил память у Windows, а в следующие разы чтобы измерять именно сборку мусора. Самый первый вызов f(N) всегда длится дольше чем все остальные (2 секунды в первый раз супротив 1.7 секунды во все остальные разы).


А вот аналогичный предыдущему код, который я написал на C#. Сразу предупреждаю, что в C# я не специалист, поэтому если вдруг я что-то написал не так, то прошу сразу ногами не пинать...

namespace TestGC
{
    class Object
    {
        public Object[] Refs;
    }

    class Program
    {
          static void Main(string[] args)
        {   
            const int N = 5000;
            System.Console.WriteLine("first memory allocation..."); f(N);
            System.Console.WriteLine("Start...");
            long t = System.Environment.TickCount;
            for (int i = 0; i < 10; i++) f(N);
            t = (System.Environment.TickCount - t) / 10;
            System.Console.WriteLine("t = {0}", t); 
            System.Console.ReadLine();
        }

        private static void f(int N)
        {
            Object[] X = new Object[N];
            for (int i = 0; i < N; i++) X[i] = new Object();
            for (int i = 0; i < N; i++)
            {
                Object[] a = new Object[N];
                for (int j = 0; j < N; j++) a[j] = X[j];
                X[i].Refs = a; 
            }
        }
    }
}

Влад использовал для измерения времени "PerfCounter", который я у себя не нашел, поэтому для измерения времени я использовал System.Environment.TickCount. Думаю, что это не сильная модификация программы Влада. Еще Object у меня не struct, а class (когда я делал ее struct, то у меня во время выполнения случалась ошибка — чего-то там не могло загрузить тип TestGC.Object из сборки TestGC). И еще есть небольшая модификация внутри главного цикла по сравнению с программой Влада. А вобщем, эта программа есть тупой буквальный перевод первой программы с языка Component Pascal на язык C#.




Результаты.
Прежде чем привести результаты, во-первых, опять же напомню, что в C# я не специалист, так что вполне мог написать кривую программу и скорость ее работы ни о чем говорить не может кроме кривизны моих рук. Во-вторых, есть следующее интересное наблюдение: Дело в том, что структура из N=5000 взаимно ссылающихся друг на друга объектов (число связей = N^2) занимает примерно 4*N^2 = 100 мегабайтов памяти. Так вот, BlackBox захватывал у Windows эти 100 мегабайтов и работал с ними "не прося добавки". Программа написанная на C# под .NET вела себя прямо противоположным образом. У меня на компе стоит 448 мегабайтов оперативки, так вот эта программа периодически захватывала все новые и новые 100 мегабайтов до тех пор пока оперативная память ни кончалась, а потом, видимо вызывался дотнетовский сборщик мусора и количество используемой памяти падало до минимума, затем серия захватов памяти по 100 мегабайтов повторялась вновь. Короче, результаты следующие:
Component Pascal     BlackBox 1.4                 t = 1.691 сек, 
C#                   MS Visual Studio .NET 2003   t = 6.375 сек,

BlackBox оказался в 6.375/1.691 = 3.77 быстрее чем .NET

Windows XP SP1, машина Celeron 1100 Coppermain 128Kb, DIMM 448Mb PC100.

Такую большую разницу я могу объяснить только тем что BlackBox только один раз взял 100 мегабайтов, а .NET то и дело захватывал по 100 мегабайтов пока вся оперативная память не исчерпывалась, а потом возвращал ее обратно повторяя все это вновь и вновь.
Re[5]: Сравнил скорости работы. Результаты потрясают воображ
От: alexeiz  
Дата: 13.11.04 23:12
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>
СГ>Component Pascal     BlackBox 1.4                 t = 1.691 сек, 
СГ>C#                   MS Visual Studio .NET 2003   t = 6.375 сек,
СГ>

СГ>BlackBox оказался в 6.375/1.691 = 3.77 быстрее чем .NET
СГ>

СГ>Windows XP SP1, машина Celeron 1100 Coppermain 128Kb, DIMM 448Mb PC100.

СГ>Такую большую разницу я могу объяснить только тем что BlackBox только один раз взял 100 мегабайтов, а .NET то и дело захватывал по 100 мегабайтов пока вся оперативная память не исчерпывалась, а потом возвращал ее обратно повторяя все это вновь и вновь.

Проверь все-таки, что C# версия компилируется в release а не в debug. У меня даже на laptop'е под mono одна секунда выходит. Конечно можно предположить, что мой laptop в 10 раз быстрее твоего desktop'а, но я в этом что-то сомневаюсь.
Re[6]: Сравнил скорости работы. Результаты потрясают воображ
От: alexeiz  
Дата: 13.11.04 23:31
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Здравствуйте, Сергей Губанов, Вы писали:


СГ>>
СГ>>Component Pascal     BlackBox 1.4                 t = 1.691 сек, 
СГ>>C#                   MS Visual Studio .NET 2003   t = 6.375 сек,
СГ>>

СГ>>BlackBox оказался в 6.375/1.691 = 3.77 быстрее чем .NET
СГ>>

СГ>>Windows XP SP1, машина Celeron 1100 Coppermain 128Kb, DIMM 448Mb PC100.

СГ>>Такую большую разницу я могу объяснить только тем что BlackBox только один раз взял 100 мегабайтов, а .NET то и дело захватывал по 100 мегабайтов пока вся оперативная память не исчерпывалась, а потом возвращал ее обратно повторяя все это вновь и вновь.

A>Проверь все-таки, что C# версия компилируется в release а не в debug. У меня даже на laptop'е под mono одна секунда выходит. Конечно можно предположить, что мой laptop в 10 раз быстрее твоего desktop'а, но я в этом что-то сомневаюсь.


Хотя, если внимательнее посмотреть, то у меня было struct Object вместо class. Когда поставил class стало в 4.5 раза медленнее. Остается только понять, RECORD в Обероне эквивалентен struct или class в C#.
Re[7]: Сравнил скорости работы. Результаты потрясают воображ
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 14.11.04 06:50
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Хотя, если внимательнее посмотреть, то у меня было struct Object вместо class. Когда поставил class стало в 4.5 раза медленнее. Остается только понять, RECORD в Обероне эквивалентен struct или class в C#.


Вопрос конечно интересный. В Component Pascal кроме RECORD ничего больше нет, так что RECORD играет роль класса. Но, может быть в C# class играет какую-нибудь еще более тяжелосвеную роль, чем просто класс объектов?
Re[5]: Сравнил скорости работы. Результаты потрясают воображ
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 14.11.04 06:53
Оценка:
Дополнительные измерения времени работы тех же программ при других N:
 N    кол.связей   один объект  вся структура   BlackBox   .NET
                                                                    
2000    4 млн         8 Kb        16 Mb          0.23 сек    0.83 сек
3000    9 млн        12 Kb        36 Mb          0.55 сек    2.27 сек
4000   16 млн        16 Kb        64 Mb          1.17 сек    3.99 сек
5000   25 млн        20 Kb       100 Mb          1.70 сек    6.37 сек
6000   36 млн        24 Kb       144 Mb          2.67 сек   10.03 сек
7000   49 млн        28 Kb       196 Mb          4.17 сек   18.12 сек
8000   64 млн        32 Kb       256 Mb          4.12 сек   22.22 сек


Component Pascal:
BlackBox 1.4, Oberon Microsystems, Inc 1994-2001, SP1.

C#:
Microsoft Development Environment 2003 Version 7.1.3088
Microsoft .NET Framework 1.1 Version 1.1.4322

Windows XP SP1, машина Celeron 1100 Coppermain 128Kb, DIMM 448Mb PC100.
Re[8]: Сравнил скорости работы. Результаты потрясают воображ
От: alexeiz  
Дата: 14.11.04 08:57
Оценка: 5 (1)
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Здравствуйте, alexeiz, Вы писали:


A>>Хотя, если внимательнее посмотреть, то у меня было struct Object вместо class. Когда поставил class стало в 4.5 раза медленнее. Остается только понять, RECORD в Обероне эквивалентен struct или class в C#.


СГ>Вопрос конечно интересный. В Component Pascal кроме RECORD ничего больше нет, так что RECORD играет роль класса. Но, может быть в C# class играет какую-нибудь еще более тяжелосвеную роль, чем просто класс объектов?


Оказывается, на время исполнения этого теста роли не играло, используется ли struct или class. Просто в случае со struct, компилятор C# создавал код, который не накапливает объекты. При выходе из самого внутреннего цикла, на них терялись все ссылки. Технически это нельзя назвать неправильным, потому что эти объекты все равно не используются за пределами функции. Поэтому я склонен полагать, что это была своего рода оптимизация, последствие которой было то, что максимальное количество активных объектов было порядка 10000, но не 25000000, как предполагалось в тесте. Из-за чего GC при каждой Gen0 сборке все недоступные объекты убирал.

Когда-же использовались классы, там было все честно. Объекты накапливались. GC старался их собрать, продвигал их в Gen1 и Gen2. Поэтому он и работает так долго. На моей машине производилось 22 Gen2 сборок, 200 Gen0 и какое-то промежуточное количество Gen1. Это слишком много. В идеальном случае должно быть, конечно, только 10 Gen0. Но .NET GC не расчитан на такой pattern использования. Он старается при первой-же возможности уменьшить рабочую память процесса насколько возможно, что хорошо и очень даже похвально, но для данной задачи неоптимально.

Наоборот, BlackBox ведет себя как единственная задача в системе. Он отнимает положенное количество памяти и никогда не освобождает её для других процессов. Даже после того, как тест заканчивается, BlackBox все равно держит память! В этом очень ярко проявляется идеалогия BlackBox'а: он сам себе операционная система. То, что есть другие процессы за его пределами, которым тоже нужна память и ресурсы, его не волнует.
Re[7]: Надо использовать class а вовсе не struct
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 14.11.04 12:55
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Хотя, если внимательнее посмотреть, то у меня было struct Object вместо class. Когда поставил class стало в 4.5 раза медленнее.



По моему использование struct вместо class попросту не удовлетворяет условию задачи. Согласно условию задачи надо динамически создать N объектов взаимно ссылающихся друг на друга (т.е. чтобы было N^2 ссылок). Поскольку struct является value-type, то обратите внимание на то что, собственно, делает следующий код:
  for (int j = 0; j < n; j++)
    a.Refs[j] = array[j];

в случае struct этот код копирует не указатель на объект, а сам объект. Так что в этом случае нет требуемых N^2 ссылок.
Re[4]: Боюсь что Ваш код не удовлетворяет условиям задачи
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 14.11.04 13:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Для сравнения тоже самое на C#:


Боюсь что Ваш код не удовлетворяет поставленной задаче. Согласно условию задачи надо динамически создать N объектов взаимно ссылающихся друг на друга (т.е. чтобы было N^2 ссылок). Поскольку struct является value-type, то обратите внимание на то что, собственно, делает следующий код:
        for (int i = 0; i < n; i++)
        {
            A a = array[i];
            a.Refs = new A[n];
            for (int j = 0; j < n; j++)
                a.Refs[j] = array[j];
        }

в случае struct этот код копирует не указатель на объект, а сам объект. Так что в этом случае нет требуемых N^2 ссылок. Вместо struct надо использовать class.

http://www.rsdn.ru/Forum/Message.aspx?mid=898100&amp;only=1
Автор: Сергей Губанов
Дата: 14.11.04
Re[5]: А как измерить скорость сборки мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.11.04 23:45
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>V = 4*N^2 = 4*5000^2 = 100 Мегабайтов


А что оберон для объектов разной внутренней информации не хранит?

СГ>Если на компе стоит 256 метров, 125 виндос себе берет, как раз остается 100 метров для программы, т.е. сборщик мусора должен срабатывать каждый раз при очередном вызове f(N).


Гы. У меня на машине гиг. Все 5 твоих вариантов идут лесом.

Однако ести ты хотел посмотреть скорость сборки мусора, то создал неудачный пример. Дело в том, что если сбошик мусора написан не идиотами, то он не будет зависить от объекма недоступных объектов. Напротив он будет зависить от объема доступных объектов. Причем для столь примитивных тестов убогии ЖЦ могут показать лучшее вермя. А вот в реальных приложениях, где часто появляется фрагментации и число несобранных объектов очень велико, тупые ЖЦ начинают отставать. Именно из-за этого в дотнете и Яве введены поколения. Они приводят к некоторому замедлению модификации ссылок, но за-то дают пратически гарантированную скорость сборки 0 и 1 поколений. В дотнете сборка 0 поколения занимает крайне мало времени (сравнимо с раскруткой стэка при вызове методов), а 1-ое поколение собирается в предалах 10 милисикунд. Учитывая, что обычно прграммы больше читают чем пишут, такой подход позволяет минимизировать тормоза сборки мусора до величин незаметных глазу.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: А как измерить скорость сборки мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.11.04 23:45
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Можно Вас попросить исправить Ваш код на следующий:

СГ>
СГ>timer.Start();
СГ>for (int i = 0; i < 10; i++)
СГ>{
СГ>  f(Size);
СГ>}
СГ>Console.WriteLine("Size = {0}, time*10 = {1}", Size, timer.Finish());
СГ>

СГ>А то ведь, действительно, вполне может оказаться, что скорость сборки мусора Ваш код не измеряет. Вдруг мусор чиститься как раз в то время когда идет вывод результатов в консоль, так что при следующей итерации цикла весь мусор уже очищен и измеряется всего лишь скорость создания структуры взаимоссылающихся объектов, но не время разрушения этой структуры.

Да без разницы. Сборка если и начтется, то как раз при выходе из метода.

К тмоу, же как я уже писал рядом, ЖЦ не собирает мертвые объекты. Так что вданном примере у него практически нет работы.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Сравнил скорости работы. Результаты потрясают воображ
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.11.04 23:45
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Влад использовал для измерения времени "PerfCounter", который я у себя не нашел,


Точное измерение производительности в дотнете
Автор: VladD2
Дата: 23.04.03


СГ>Такую большую разницу я могу объяснить только тем что BlackBox только один раз взял 100 мегабайтов, а .NET то и дело захватывал по 100 мегабайтов пока вся оперативная память не исчерпывалась, а потом возвращал ее обратно повторяя все это вновь и вновь.


А ты верни struct на место и все будт ОК. К тому же называть класс Object в дотнете не очень хорошая идея (это имя встроенного типа).

PS

Что до сравнения ЖЦ, так надо сравнивать его на реальных задачаях, а не на подобной туфте. Тут ты меряешь время заполнения ссылк. ЖЦ же вообще не работает (удалять то нечего). А вот в реальном приложении расклад будет совсем другой. Ведь модификаций ссылок будет чуть, а вот сборка мустора будет действительно серьезной задачей. Похоже, что Блэкбокс оптимизаций не делает. По этому время заполнения у него выше. К тому же минимальный объект в дотнете == 8 байтам. Так что и каждый объект и каждый массив в дотнете хранит лишние 8 байт.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Сравнил скорости работы. Результаты потрясают воображ
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.11.04 23:45
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Хотя, если внимательнее посмотреть, то у меня было struct Object вместо class. Когда поставил class стало в 4.5 раза медленнее. Остается только понять, RECORD в Обероне эквивалентен struct или class в C#.


stract. stract распологается по месту и не хранит лишних данных. class — это ссылочный тип, т.е. хранит лишние 8 байт и всегда создается в куче (в массиве хранятся ссылки).
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Как "уронить" сборщик мусора?
От: Дарней Россия  
Дата: 15.11.04 07:50
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Трепачь находка для шпионов. Если ЖЦ видет что финалайзер занят более чем на определенное время, то плюет на финализацию и продолжает работу.


А вот тут ты не совсем прав. GC забивает на финализацию только в том случае, когда происходит закрытие процесса.
Если же происходит работа в обычном режиме, то тред финализации подвисает намертво и висит, пока не будет закрыт процесс. Так что все время жизни процесса будет происходить утечка памяти (понятно, что при этом для объектов без финалайзера никаких проблем не будет).
По крайней мере, таково положение в 1.0. и 1.1
Насчет 2.0 не знаю
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[6]: Так все таки?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 15.11.04 08:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Точное измерение производительности в дотнете
Автор: VladD2
Дата: 23.04.03


Спасибо.

VD>А ты верни struct на место и все будт ОК. К тому же называть класс Object в дотнете не очень хорошая идея (это имя встроенного типа).


По условию задачи надо создать N объектов и N^2 ссылок между ними. И лишь только после создания надо натравить на эту структуру сборщик мусора и посмотреть как он с этим справится. Поскольку struct является типом-значением, то использовать его нельзя. Для получения N^2 ссылок нужно использовать ссылочный тип, то есть нужно использовать class.

Ваш код:
        for (int i = 0; i < n; i++)
        {
            A a = array[i];
            a.Refs = new A[n];
            for (int j = 0; j < n; j++)
                a.Refs[j] = array[j];
        }

в том случае когда "A" есть тип-значение есть просто N^2 копирований значений объектов, а надо было создать N^2 ссылок. Так что тип "A" должен быть class, а не struct.

VD> Что до сравнения ЖЦ, так надо сравнивать его на реальных задачаях, а не на подобной туфте.


Во-первых, N^2 взаимных ссылок между N объектами есть максимально возможное количество (разных) взаимных ссылок. Так что этот случай есть случай с максимально возможным количеством (разных) взаимных ссылок. Любые другие случаи всегда имеют меньшее количество (разных) взаимных ссылок. Следовательно, назвать это "туфтой" уже нельзя.
Во-вторых, даже на этой, с Вашего позволения сказать "туфте", как оказалось, сборщик мусора в BlackBox работает в несколько раз (от 3.41 раза) быстрее сборщика мусора .NET:
 N    кол.связей   один объект  вся структура   BlackBox   .NET        Отношение времен .NET/BlackBox
                                                                    
2000    4 млн         8 Kb        16 Mb          0.23 сек    0.83 сек    3.60 раз
3000    9 млн        12 Kb        36 Mb          0.55 сек    2.27 сек    4.13 раз
4000   16 млн        16 Kb        64 Mb          1.17 сек    3.99 сек    3.41 раз
5000   25 млн        20 Kb       100 Mb          1.70 сек    6.37 сек    3.75 раз
6000   36 млн        24 Kb       144 Mb          2.67 сек   10.03 сек    3.76 раз
7000   49 млн        28 Kb       196 Mb          4.17 сек   18.12 сек    4.35 раз
8000   64 млн        32 Kb       256 Mb          4.12 сек   22.22 сек    5.39 раз

Впрочем, если Вы называете это "туфтой", то предложите пожалуйста, какую-нибудь другую задачу, которая на Ваш взгляд не являлась бы "туфтой".

VD> Тут ты меряешь время заполнения ссылк. ЖЦ же вообще не работает (удалять то нечего).


Я-то, как раз измеряю "время создания структуры" + "время сборки мусора". А вот Вы используя struct вместо class не создавали ссылок, следовательно, и в самом деле не измеряли скорость работы GC, надо было использовать class.

VD> К тому же минимальный объект в дотнете == 8 байтам. Так что и каждый объект и каждый массив в дотнете хранит лишние 8 байт.


Естественно, BlackBox тоже для каждого объекта хранит указатель на дескриптор типа, так что реальный размер объекта на самом деле чуть больше чем сумма размеров его полей, ну и что из этого следует? Какая, по большому счету, разница имеет ли объект размер V = 4*N байтов или V = 4*N + delta, где delta ~ 8 байтов, в тех случаях когда N = 2000, ..., N = 8000? Думаю разницы никакой...
Re[7]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.11.04 14:21
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>А вот тут ты не совсем прав. GC забивает на финализацию только в том случае, когда происходит закрытие процесса.


Я совсем прав. Финалайзеры вызываются зи отдельного потока

Д>Если же происходит работа в обычном режиме, то тред финализации подвисает намертво и висит, пока не будет закрыт процесс. Так что все время жизни процесса будет происходить утечка памяти (понятно, что при этом для объектов без финалайзера никаких проблем не будет).

Д>По крайней мере, таково положение в 1.0. и 1.1
Д>Насчет 2.0 не знаю

И где ты взял такие свленения?
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Как "уронить" сборщик мусора?
От: Дарней Россия  
Дата: 16.11.04 04:46
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Я совсем прав. Финалайзеры вызываются зи отдельного потока


я знаю
тем не менее — пока этот поток висит, ни один объект с финалайзером не будет освобожден

VD>И где ты взял такие свленения?


просто небольшой эксперимент — можешь сам проверить, кстати.
еще про это написано у Рихтера. "Программирование на платформе .NET" (первое издание), с. 396
RTFM
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[9]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.11.04 14:58
Оценка: -1
Здравствуйте, Дарней, Вы писали:

Д>я знаю

Д>тем не менее — пока этот поток висит, ни один объект с финалайзером не будет освобожден

Он не может висеть более определенного промежутка времени (если не ошибаюсь 2 секунд).

VD>>И где ты взял такие свленения?


Д>просто небольшой эксперимент — можешь сам проверить, кстати.


Ты лучше не советуй другим, а сам попробуй. Я то пробовал не раз. Никаких проблем нет.

Д>еще про это написано у Рихтера. "Программирование на платформе .NET" (первое издание), с. 396

Д>RTFM

И что же ты там вычитал. Почти уверен, что просто не понял доконца, что написано.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Как "уронить" сборщик мусора?
От: Дарней Россия  
Дата: 17.11.04 05:49
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Он не может висеть более определенного промежутка времени (если не ошибаюсь 2 секунд).


тестовый пример — в студию!

VD>Ты лучше не советуй другим, а сам попробуй. Я то пробовал не раз. Никаких проблем нет.


значит, плохо пробовал

VD>И что же ты там вычитал. Почти уверен, что просто не понял доконца, что написано.


Перепечатывать из книги нет никакого желания. Не могу поверить, что у тебя под рукой нет ни одного экземпляра.
Когда кажется — креститься надо. Если можешь показать, что именно я там неправильно понял — флаг в руки. Если нет — попрошу воздержаться от ничем не обоснованных утвержений.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[7]: Так все таки?
От: Трурль  
Дата: 17.11.04 06:30
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Естественно, BlackBox тоже для каждого объекта хранит указатель на дескриптор типа, так что реальный размер объекта на самом деле чуть больше чем сумма размеров его полей, ну и что из этого следует? Какая, по большому счету, разница имеет ли объект размер V = 4*N байтов или V = 4*N + delta, где delta ~ 8 байтов, в тех случаях когда N = 2000, ..., N = 8000? Думаю разницы никакой...

Маленькая поправка не по существу: delta = 4.
Re[11]: Как "уронить" сборщик мусора?
От: vdimas Россия  
Дата: 17.11.04 13:21
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>Перепечатывать из книги нет никакого желания. Не могу поверить, что у тебя под рукой нет ни одного экземпляра.

Д>Когда кажется — креститься надо. Если можешь показать, что именно я там неправильно понял — флаг в руки. Если нет — попрошу воздержаться от ничем не обоснованных утвержений.

да ты хоть страницу скажи, интересно стало
Re[12]: Как "уронить" сборщик мусора?
От: Дарней Россия  
Дата: 17.11.04 14:00
Оценка:
Здравствуйте, vdimas, Вы писали:

V>да ты хоть страницу скажи, интересно стало


http://gzip.rsdn.ru/Forum/Message.aspx?mid=900243&amp;only=1
Автор: Дарней
Дата: 16.11.04
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[12]: Как "уронить" сборщик мусора?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.11.04 14:26
Оценка: :)
Здравствуйте, vdimas, Вы писали:

V>да ты хоть страницу скажи, интересно стало


Можно и без Рихтера. Тест примерно такой:
using System;
using System.Threading;

class Test
{
    static void Main()
    {
        Test t = new Test();
        GC.Collect();
        Thread.Sleep(-1);
    }

    ~Test()
    {
        while (true)
        {
            Thread.Sleep(1000);
            Console.WriteLine(DateTime.Now);
        }
    }
}
... << RSDN@Home 1.1.4 beta 3 rev. 230>>
AVK Blog
Re[11]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.11.04 17:26
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>тестовый пример — в студию!


Re[4]: Как "уронить" сборщик мусора?
Автор: xvost
Дата: 12.11.04


VD>>Ты лучше не советуй другим, а сам попробуй. Я то пробовал не раз. Никаких проблем нет.


Д>значит, плохо пробовал


Так попробуй хорошо.

VD>>И что же ты там вычитал. Почти уверен, что просто не понял доконца, что написано.


Д>Перепечатывать из книги нет никакого желания. Не могу поверить, что у тебя под рукой нет ни одного экземпляра.


А накой он мне под рукой?

Д>Когда кажется — креститься надо.


Перекристился?

Д> Если можешь показать, что именно я там неправильно понял — флаг в руки.


Для этого ты должен процитировать участок на основании которого ты сделал подобное заключение.

Д> Если нет — попрошу воздержаться от ничем не обоснованных утвержений.


Примени эти слова к себе.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Как "уронить" сборщик мусора?
От: Дарней Россия  
Дата: 18.11.04 04:59
Оценка: 107 (8)
Здравствуйте, VladD2, Вы писали:

VD>Так попробуй хорошо.


using System;
using System.Threading;

class Test
{
    class TestClass1
    {
        ~TestClass1()
        {
            while (true)
            {
                Thread.Sleep(1000);
                Console.Write("1 ");
                Console.WriteLine(DateTime.Now);
            }
        }
    }

    class TestClass2
    {
        ~TestClass2()
        {
            while (true)
            {
                Thread.Sleep(1000);
                Console.Write("2 ");
                Console.WriteLine(DateTime.Now);
            }
        }
    }

    static void Main()
    {
        TestClass1 t1 = new TestClass1();
        t1 = null;
        TestClass2 t2 = new TestClass2();
        t2 = null;
        while (true)
        {
            GC.Collect();
        }
    }

}

Проверено на VS2003

Нетрудно убедиться, что финалайзер одного из объектов выполняется бесконечно долго, а другой объект так же бесконечно стоит в очереди freachable. Что и требовалось доказать.

VD>А накой он мне под рукой?


Я всегда думал, что любой толковый програмер под .NET должен иметь эту книгу под рукой. Или как минимум ее прочитать. И понять

VD>Для этого ты должен процитировать участок на основании которого ты сделал подобное заключение.


Там написано очень просто.
"Если метод Finalize .... попадает в бесконечный цикл, этот особый поток блокируется, и ни один метод Finalize больше не может быть вызван. Это очень скверная ситцация: приложение больше не сможет освобождать память, занятую завершаемыми объектами, и на протяжении всей работы приложения будет происходить утечка памяти."
Ваши комментарии?

VD>Примени эти слова к себе.


Я свои слова и до этого прекрасно обосновал. А теперь — еще лучше Так что если ты сумеешь доказать, что я не прав, то я готов съесть свою собственную шапку
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[7]: Как "уронить" сборщик мусора?
От: vdimas Россия  
Дата: 18.11.04 14:17
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>А вот тут ты не совсем прав. GC забивает на финализацию только в том случае, когда происходит закрытие процесса.

Д>Если же происходит работа в обычном режиме, то тред финализации подвисает намертво и висит, пока не будет закрыт процесс. Так что все время жизни процесса будет происходить утечка памяти (понятно, что при этом для объектов без финалайзера никаких проблем не будет).

ну и что это доказывает?
разумеется финализация производиться в отдельном потоке, в порядке очереди.
для объектов без финализатора утечек не будет.
Re[8]: Как "уронить" сборщик мусора?
От: Дарней Россия  
Дата: 18.11.04 14:31
Оценка:
Здравствуйте, vdimas, Вы писали:

V>ну и что это доказывает?


это доказывает, что утечка все-таки может происходить — даже если ссылок на объект в коде не осталось

V>для объектов без финализатора утечек не будет.


у большого количества классов он есть
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[13]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.11.04 03:09
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>Нетрудно убедиться, что финалайзер одного из объектов выполняется бесконечно долго, а другой объект так же бесконечно стоит в очереди freachable. Что и требовалось доказать.


Нда. Значит я спутал с завершением процесса. При завершении процесса он точно срубается в течении нескольких секунд.

VD>>А накой он мне под рукой?


Д>Я всегда думал, что любой толковый програмер под .NET должен иметь эту книгу под рукой. Или как минимум ее прочитать. И понять


Вот я когда-то ее прочитал и куда-то засунул. Откровенно говоря так-как попала ко мне в руки она слишком поздно, толку от нее особого небыло. Было несколько интересных моментов, но пользы от них на практие не много. Те же финалайзеры довольно бесполезны сами по себе, чтобы на них закладываться. Хотя труд конечно основательный. Рихтер держит марку.

Д>Там написано очень просто.

Д>"Если метод Finalize .... попадает в бесконечный цикл, этот особый поток блокируется, и ни один метод Finalize больше не может быть вызван. Это очень скверная ситцация: приложение больше не сможет освобождать память, занятую завершаемыми объектами, и на протяжении всей работы приложения будет происходить утечка памяти."
Д>Ваши комментарии?

Да, все верно. Только это не говорит о том, что ЖЦ перестанет работать, или поток финализации не будет убит никогда.

Д>Я свои слова и до этого прекрасно обосновал.


Сейчас вот обосновал. А до этого не очень то.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Как "уронить" сборщик мусора?
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.11.04 03:09
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>это доказывает, что утечка все-таки может происходить — даже если ссылок на объект в коде не осталось


Финалайзеры настолько недетерминированная вещь, что закладваться на них нельзя даже если бы они обеспечивали 100%-ую гарантию отрабатывания.

Их можно рассматривать только как дополнительный сервис дающий еще один шанс безалаберной программе. Я вот как-то ни одного за три года не написал (если не считать тесты).

V>>для объектов без финализатора утечек не будет.


Д>у большого количества классов он есть


Ошибашся. У относительно малого. К тому же даже если он есть — это еще не значит, что объект попадет в очередь финализации. Большинство объектов у которых реализован финалайзер так же реализован и IDisposable.Dispose(), который обычно делается по следующеей схеме:
public void Dispose()
{
      this.Dispose(true);
      GC.SuppressFinalize(this);
}

то есть после вызова Dispose объект принудительно удаляется из очереди финализации. Так что в эту очередь попадают или потерянные объекты, или не очень добротно написанные.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Как "уронить" сборщик мусора?
От: Дарней Россия  
Дата: 19.11.04 05:02
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>Нда. Значит я спутал с завершением процесса. При завершении процесса он точно срубается в течении нескольких секунд.


угу, так оно и есть

VD>Вот я когда-то ее прочитал и куда-то засунул. Откровенно говоря так-как попала ко мне в руки она слишком поздно, толку от нее особого небыло. Было несколько интересных моментов, но пользы от них на практие не много. Те же финалайзеры довольно бесполезны сами по себе, чтобы на них закладываться. Хотя труд конечно основательный. Рихтер держит марку.


ИМХО, в .NET финалайзеры вообще не надо было реализовывать — Dispose вполне достаточно. А то слишком уж часто встречаются примеры неправильного использования финалайзеров

VD>Да, все верно. Только это не говорит о том, что ЖЦ перестанет работать, или поток финализации не будет убит никогда.


убит то будет... но только при закрытии процесса
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[10]: Как "уронить" сборщик мусора?
От: Дарней Россия  
Дата: 19.11.04 05:03
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>то есть после вызова Dispose объект принудительно удаляется из очереди финализации. Так что в эту очередь попадают или потерянные объекты, или не очень добротно написанные.


в принципе — так оно и есть.. так что это можно считать еще одной причиной не использовать финалайзеры
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re: Резюме
От: lextasy Украина www.mira-tech.com.ua
Дата: 20.11.04 11:50
Оценка:
Выходиит, "по-честному" GC завалить невозможно.
Что неудивительно в силу его внутренней простоты и отсутствия каких-либо революционных "ноу-хау", доселе неиспытанных в индустрии.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.