Слышал, что можно как-то хитрым образом написать программу так, что сборщик мусора уйдет в глубокий даун разгребая мусор, короче будет работать неэффективно. Правда это или миф? Если у кого есть конкретные примеры таких программ — поделитесь, пожалуйста.
В свою очередь, попробовал испытать пронырливость сборщика мусора. Рассуждал так: чем больше ссылок между объектами — тем хуже для сборщика мусора. Если у нас есть 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.