Как "уронить" сборщик мусора?
От: Сергей Губанов Россия 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.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.