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? Думаю разницы никакой...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.