Сборщик мусора необходим для компонентно ориентированного программирования.
Вот, вынес в отдельную ветку тему о необходимости сборщика мусора в компонентно ориентированных системах. Более десяти лет назад люди поняли, что полноценные компонентные (модульные) системы невозможны без наличия единого сборщика мусора. Мне, видимо, по неосторожности удалось упомянуть об этом факте на этом форуме. После чего на меня посыпались шишки и упреки вплоть до категоричного — "бред сивой кобылы", что мол сборщик мусора — это только для удобства, и теоретически все delete можно расставить в момент написания модуля (компонента).
По моему, очевидно, что задача расстановки delet-ов на момент написания модуля не имеет решения — НЕРАЗРЕШИМА статически. Ее надо решать динамически во время работы программы, а поскольку только сама система исполнения модулей знает о том какие модули в данный момент загружены и какие объекты они насоздавали, то динамическую задачу освобождения памяти должна решать сама среда исполнения. Примеры таких сред исполнения: всякие клоны ОС Оберон, ОС Inferno, Java VM, .NET и т. д.; Каждая из этих сред, само-собой, является и первичным загрузчиком модулей.
Некоторые упоминали еще среду COM. Но она имеет ограничение — там уборка мусора идет по подсчету ссылок. Стало быть циклические ссылки там запрещаются. Меня даже упрекали в том что циклические ссылки — это проё<sensored>, в смысле большая ошибка проектировщика. Но ссылки между объектами не имеют к проектировщику ничего общего, они диктуются предметной областью. Просто COM объектны из-за запрета на циклические ссылки не пригодны для моделирования ряда предметных областей: Роль Мужа <--> Роль Жены, Роль Друга <--> Роль Друга, Роль Матери <--> Роль Ребенка, Роль Учителя <--> Роль Ученика, Роль Начальника <--> Роль Подчиненного, Роль Работодателя <--> Роль Работника, Роль Компании <--> Роль Сотрудника, Роль Государства <--> Роль Гражданина, Роль Врача <--> Роль Больного; моделирование ориентированных графов и т.п.
Еще раз напомню, что речь идет о компонентных (т.е. модульных) системах — таких когда модули общаются друг с другом с помощью передачи друг другу объектов (адресов объектов, полиморфных переменных,...). Ну, а внутри одного единственного модуля для его внутренних переменных адреса которых никогда не сообщаются внешним модулям, delet-ы расставить теоретически можно, если не лень.
Re: Сборщик мусора необходим для компонентно ориентированног
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Сборщик мусора необходим для компонентно ориентированного программирования.
<>
Ну, помимо подсчёта ссылок (как разновидности сборки мусора на деревьях), существует механизм сборки мусора на графах.
Он более сложен в реализации, поскольку требует, во-первых, централизованного менеджера, а во-вторых, обработки связей контейнер-член.
Последнее делается либо на уровне языка (smalltalk, java, .net), либо с помощью танцев с бубном.
Для сравнения:
В паскале и C, при удалении объекта (сборка мусора от корня к листьям) нужно вручную удалить всех членов этого объекта. В C++ деструктор автоматизируется на уровне языка.
В C++ пометка членов (обход графа владения) осуществляется вручную; в C# — на уровне языка.
Перекуём баги на фичи!
Re: Сборщик мусора необходим для компонентно ориентированног
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Сборщик мусора необходим для компонентно ориентированного программирования.
SYG>...Более десяти лет назад люди поняли, что полноценные компонентные (модульные) системы невозможны без наличия единого сборщика мусора.
Очень похоже на утверждение про "настоящего шотландца": "А вот...". Я же сказал: "Полноценные системы".
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Сборщик мусора необходим для компонентно ориентированного программирования.
Он также крайне желателен для любого серверного приложения, поскольку чем дольше работает программа, тем тяжелее управлять памятью вручную. Дефрагментация памяти — это ведь не шуточки.
Re: Сборщик мусора необходим для компонентно ориентированног
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Мне, видимо, по неосторожности удалось упомянуть об этом факте на этом форуме. После чего на меня посыпались шишки и упреки вплоть до категоричного — "бред сивой кобылы", что мол сборщик мусора — это только для удобства, и теоретически все delete можно расставить в момент написания модуля (компонента).
Да это не здесь, а вообще. Люди просто очень не любят рушить свои убеждения. Кто-то когда-то сказал, что GC (а точнее Java, но раз Java то и GC тоже) — это отстой. И все повторяют как попугаи.
А ведь GC используется скорее не ради удобства, а ради решения проблемы фрагментации. И как раз в сильно фрагментируемых системах GC намного эффективнее обычных куч (Это теоритически доказано!).
Re[2]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Кодт, Вы писали:
К>Для сравнения: К>В паскале и C, при удалении объекта (сборка мусора от корня к листьям) нужно вручную удалить всех членов этого объекта. В C++ деструктор автоматизируется на уровне языка. К>В C++ пометка членов (обход графа владения) осуществляется вручную; в C# — на уровне языка.
Что ты имешь в виду под "на уровне языка"?
Ну, и ты как-нить определись таки в C# или в .net?
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, adb, Вы писали:
adb>Да это не здесь, а вообще. Люди просто очень не любят рушить свои убеждения. Кто-то когда-то сказал, что GC (а точнее Java, но раз Java то и GC тоже) — это отстой. И все повторяют как попугаи. adb>А ведь GC используется скорее не ради удобства, а ради решения проблемы фрагментации. И как раз в сильно фрагментируемых системах GC намного эффективнее обычных куч (Это теоритически доказано!).
Соглашусь, что GC вещь полезная, но многие существующие реализации языков с GC имеют ряд недостатков. Вот примеры:
1) быстродействие — ну это всем набило оскомину, по этому пункту даже спорить не буду, потому как в оправдание обычно приводят результаты искусственных тестов, которые не доказывают ничего; но вот когда быстродействие яаляется существенным ограничением, от GC обычно отказываются;
2) как ни парадоксально звучит, но существующие реализации языков с GC усложняют процесс освобождение ресурсов. Постараюсь объяснить последний пункт, так как считаю его одним из самых серьёздных конструктивных просчётов. В C++ принята техника "выделение ресурса — есть инициализация", суть которой сводится к следующему — для управления некоторым ресурсом (файлом, дескриптором ядра ОС) пишется обёртка, которая в конструкторе выполняет открытие (захват) ресурса, а в деструкторе его закрытие освобождение. Если в некотрой локальной области вам нужен ресурс вы просто объявляете соответствующую статическую переменную, при выходе из этой области — нормально или вследствии исключения — вызывается деструктор и ресурс освобождается. Таким образом вам не надо следить за освобождением этого ресурса, не надо оборачивать всю область try-catch`ем, не надо вручную вызывать методы типа close и бла-бла-бла. Техника "выделение ресурса — есть инициализация" является очень гармоничным дополнением техники обработки ошибок через сборс исключений. Я уверен, что многие всё это знают и без меня. А теперь внимание, все наиболее распространённые языки с GC в качестве механизма обработки ошибок используют исключения, но ни один из них не поддерживает технику "выделение ресурса — есть инициализация". Вы скажите, ну это естественно, ведь ни кто не знает, когда сработает GC и будет вызван деструктор и будете не правы — в C# есть понятие размерных типов, которые существуют только в пределах локальной области видимости и уничтожаются при выходе из неё, по-моему, вполне разумная идея и вполне разумным продолжением этой идеи было бы добавления к ним деструктора. Но нет деструктор там запрещён.
Итог, в существующих языках с GC последний превосходно собирает память, но усложняет процесс освобождения других ресурсов, таких как файлы, дескрипторы ОС, сокеты и прочее.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[3]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Mr. None, Вы писали:
MN>Итог, в существующих языках с GC последний превосходно собирает память, но усложняет процесс освобождения других ресурсов, таких как файлы, дескрипторы ОС, сокеты и прочее.
В Java просто используется другой подход. Там не просто try-catch, а try-catch-finally. Finally как раз и предназначен для освобождения ресурсов. С одной стороны менее удобно, с другой стороны более прозрачно.
Re[4]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, adb, Вы писали:
adb>Здравствуйте, Mr. None, Вы писали:
MN>>Итог, в существующих языках с GC последний превосходно собирает память, но усложняет процесс освобождения других ресурсов, таких как файлы, дескрипторы ОС, сокеты и прочее.
adb>В Java просто используется другой подход. Там не просто try-catch, а try-catch-finally. Finally как раз и предназначен для освобождения ресурсов. С одной стороны менее удобно, с другой стороны более прозрачно.
В .NET`е то же самое, но согласитесь, что такой псевдокод:
// Обобщённый пример - .NET, Java
void func()
{
File inFile = new File();
inFile.Open("test.dat");
try
{
// Тонна кода, где кто-то может сгенерировать исключение
}
finally
{
if(inFile.IsOpened()) // Не забыть проверить, на всякий случай
{
inFile.Close();
}
}
}
меннее удобен чем такой:
// С++void func()
{
File inFile;
inFile.Open("test.dat");
// Тонна кода, где кто-то может сгенерировать исключение
}
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[5]: Сборщик мусора необходим для компонентно ориентирован
Это разные равноценные подходы. Не более. Только один предлагает явно высвобождать ресурсы, а второй неявно. При этом, как я уже сказал, во втором случае мы платим прозрачностью кода за удобство написания.
Re[6]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, adb, Вы писали:
adb>Это разные равноценные подходы. Не более. Только один предлагает явно высвобождать ресурсы, а второй неявно. При этом, как я уже сказал, во втором случае мы платим прозрачностью кода за удобство написания.
Я бы не назвал первый вариант ни прозрачным, ни удобным... Это именно пример непродуманной концепции в погоне за модной фичей — GC это круто и пошли огалтело отрицать всё что было до него, лишь бы быстрее выпустить релиз новой платформы. А потом за месяц до выхода продукта, когда написана тона кода начинают появляться операторы типа using:
void func()
{
using(File inFile = new File("test.dat"))
{
// Тонна кода
}
// Здесь автоматически будет вызван inFile.Dispose()
}
Аллилуйя, спустился бог на землю — это уже лучше, но если бы сразу чуть-чуть подумать и не гнать впереди паравоза ! Куда гармоничнее смотрелся бы вариант с разрешением деструкторов у размерных типов... И сишникам переучиваться не надо было бы... И жабисты довольны — try/finaly есть...
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[6]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, adb, Вы писали:
adb>Это разные равноценные подходы. Не более. Только один предлагает явно высвобождать ресурсы, а второй неявно. При этом, как я уже сказал, во втором случае мы платим прозрачностью кода за удобство написания.
Прозрачность блин В лес такую прозрачность.
ручное слежение за ресурсами и увеличение обьема кода -> увеличение вероятности ошибки и затуманивание логики
А плюсов не вижу.
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Mr. None, Вы писали:
MN>Соглашусь, что GC вещь полезная, но многие существующие реализации языков с GC имеют ряд недостатков. Вот примеры: MN>1) быстродействие — ну это всем набило оскомину, по этому пункту даже спорить не буду, потому как в оправдание обычно приводят результаты искусственных тестов, которые не доказывают ничего; но вот когда быстродействие яаляется существенным ограничением, от GC обычно отказываются;
Это миф. Вот ссылка http://cern.ch/oberon.day/talks/ftkachov.pdf Физик-теоретик Федор Ткачев тестировал оберон-систему BlackBox на научных расчетах в области квантовой теории поля (согласитесь быстродействие там ОЧЕНЬ нужно)
Результаты
BlackBox 1.4 Component Pascal 3.6 +/- 0.1 sec (With all safety check, with all debuging info)
MS Visual Studio 6.0 C++ 9.3 +/- 0.1 sec (debug)
MS Visual Studio 6.0 C++ 3.5 +/- 0.1 sec (Full speed optimization, O(10) slower compilation)
В пределах точности измерений (+/- 0.1 sec) BlaclkBox 1.4 работает также быстро как и MS Visual Studio 6.0, причем в Component Pascal кроме сборщика мусора тормоза создавали еще и никогда не отключаемая проверка индексов массива и никогда не отключаемая проверка переполнения при арифметических операциях, по сути — это "дебажная версия".
MN>2) как ни парадоксально звучит, но существующие реализации языков с GC усложняют процесс освобождение ресурсов.
Причина этой проблемы кроется совсем в другом. Когда Вы говорите "освобождение ресурсов", то имеете ввиду, что система со сборкой мусора работает поверх обычной древней системы и что Вы вынуждены пользоваться вот таким вот кодом:
f := FileOpen('a.txt');
где функция FileOpen — это APIшная функция древней операционки не имеющей сборщика мусора. То есть проблема состоит во взаимодейсвии современных managed систем со старыми unmanaged системами. Такая проблема есть в Java так как Java, являясь виртуальной машиной, всегда работает поверх какой-то другой реальной машины. В Оберон-системах такой проблемы нет потому что там вся операционка написана от начала и до конца в объектно ориентированном стиле учитывающем сборщик мусора (сборщик мусора интегрирован в саму ОСь). Там в самой операционке просто нету таких опасных низкоуровневых функций как OpenFile(), CloseFile(), а значит и нету проблем связанных с Вашим "освобождением ресурсов". Я уже писал об этом: http://www.rsdn.ru/Forum/Message.aspx?mid=725451&only=1
SYG>Это, мягко говоря, немного устаревший способ работы с файлами. Всвязи с появлением ООП, люди уже более десятка лет с файлами работают на более высоком уровне абстракции. Могу вкратце описать как это делается в системе BlackBox от Oberon Microsystems. В этой системе для этой цели используется паттерн проектирования под названием "Carrier-Rider-Mapper". Carrier — это персистентный объект содержащий внутри себя какие-либо данные (можно думать о нем как об объектно-ориентированном аналоге устаревшего понятия — "файл"). Для простоты примера давайте предположим, что речь идет о файле с текстом. Carrier — это персистентный объект внутри которого инкапсулирован текст. Доступ к этому тексту одновременно можно предоставить сразу нескольким клиентам, например, открыть несколько окон с одним и тем же содержимым. Каждый клиент должен, как минимум, знать в каком месте текста он в данный момент имеет "текущую позицию". Так как количество клиентов произвольное, то информация о текущей позиции не может хранится в самом объекте Carrier, для этих целей объект Carrier умеет создавать так называемые Rider-объекты (паттерн — "итератор"). Так что клиенты обращаются не на прямую к объекту Carrier, а посредством Rider-ов. Между Carrier-ом и Rider-ами существует отношение один-ко-многим. Аналогично Rider-ам объект Carrier может создавать объекты Writer-ы, которые умеют "писать", в отличие от "читающих" Rider-ов. На этом приключения не заканчиваются. Кроме Carrier, Rider-ов и Writer-ов существуют еще так называемые Mapper-ы. Дело в том что Rider-ы и Writer-ы представляют низкоуровневый интерфейс (теоретически, вплоть до: записать один байт, прочитать один байт). Mapper-ы — это объекты-прослойки между Rider-ами, Writer-ами и клиентами. Они предоставляют более высокоуровневый уже проблемно-ориентированный набор операций для чтения и записи. Разные приложения могут использовать разные Mapper-ы работая с одним и тем же Carrier-ом.
SYG>Пример: SYG>Client <-- Scanner <-- Reader <-- Carrier SYG>Client --> Formatter --> Writer --> Carrier
SYG>Scanner и Formatter — это Mapper-ы.
SYG>Вобщем, клиенты общаются с Carrier-ом даже не через Reader/Writer, а через Mapper-ы. Сами Reader/Writer-ы нужны для того чтобы предотвратить комбинаторный взрыв количества реализаций разных мапперов под разные кариеры. Если есть n-штук Carrier-ов и m-штук Mapper-ов, то в этом случае надо написать реализацию только для n+m полиморфных переменных, а вовсе не для n*m как могло бы быть без Reader/Writer-ов.
SYG>Теперь вернемся к Вашему вопросу о "забыть сделать file.Close() то фаил не будет закрыт до сборки мусора". Понимаете в чем дело-то, клиент понятия не имеет о том сколько еще других клиентов приконнекчено к Carrier-у, а значит клиент в принципе не может выполнить операцию file.Close(), в интерфейсах форматтеров, райдеров, врайтеров и карьеров такой операции нет по принципиальным причинам. Подконнекчиваясь к кариеру клиенту совершенно безразлично был ли это кариер только что создан (только что открыли файл) или он уже существовал (файл уже был открыт кем-то другим). Клиент получает в свое пользование Carrier-скую полиморфную переменную и делает с ней что хочет, а потом забывает о ней. Так же поступают другие клиенты. Сам же Carrier являясь персистентным объектом, всегда существует в единственном экземпляре, то есть Ваши опасения по забывчивости открыть несколько раз один и тот же файл совершенно напрасны (работает некоторая модификация паттерна Singleton).
Не надо быть провидцем чтобы предугадать что в новой микрософтовской операционке Longhorn что-то вроде сборщика мусора будет интегрировано в нее саму — спохватились ковбои спустя 10 лет, чтоже, лучше поздно чем никогда.
Re[4]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Причина этой проблемы кроется совсем в другом. Когда Вы говорите "освобождение ресурсов", то имеете ввиду, что система со сборкой мусора работает поверх обычной древней системы и что Вы вынуждены пользоваться вот таким вот кодом:
Не поверх обычной древней системы, а во взаимодействии.
И если в пределах одного приложения и даже одного компьютера можно попытаться сделать всё управляемым (managed), то навязывать управляемость внешнему миру — это большой-пребольшой вопрос.
Пример: удалённый сервер.
Соединение с сервером — это ресурс для клиента, и соответственно, соединение с клиентом — ресурс для сервера.
Если даже клиенту пофиг и он надеется на сборку мусора (которая помимо памяти приберёт и все незакрытые соединения), то для сервера сотня-другая таких разгильдяйских клиентов обернутся DoS'ом.
Ещё пример: получили ресурс в монопольном режиме. Все остальные курят до скончания века.
Не надо тут говорить, что к файлам можно делать раздельный доступ... Порты — это тоже ресурсы.
Как в оберон-системе решается вопрос с ком-портом?
Перекуём баги на фичи!
Re[4]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Здравствуйте, Mr. None, Вы писали:
MN>>Соглашусь, что GC вещь полезная, но многие существующие реализации языков с GC имеют ряд недостатков. Вот примеры: MN>>1) быстродействие — ну это всем набило оскомину, по этому пункту даже спорить не буду, потому как в оправдание обычно приводят результаты искусственных тестов, которые не доказывают ничего; но вот когда быстродействие яаляется существенным ограничением, от GC обычно отказываются;
SYG>Это миф. Вот ссылка http://cern.ch/oberon.day/talks/ftkachov.pdf Физик-теоретик Федор Ткачев тестировал оберон-систему BlackBox на научных расчетах в области квантовой теории поля (согласитесь быстродействие там ОЧЕНЬ нужно) SYG>В пределах точности измерений (+/- 0.1 sec) BlaclkBox 1.4 работает также быстро как и MS Visual Studio 6.0, причем в Component Pascal кроме сборщика мусора тормоза создавали еще и никогда не отключаемая проверка индексов массива и никогда не отключаемая проверка переполнения при арифметических операциях, по сути — это "дебажная версия".
Извините не соглашусь — чрезмерное быстродействие там нафиг не нужно. Расчёты выполняются не в реальном времени. Вот пример систем, где быстродействие действительно критично:
слежение за спутником связи;
коммутация каналов на АТС;
контроль стыковки грузовика с космической станцией;
слежение за состоянием лифтов в здании и прочее и прочее...
Так вот открою вам тайну для управления такими системами даже операционки специальные пишутся, где всего по минимуму, главное чтобы реакция на внешний раздражитель была в пределах милисекунды. На крайний случай пойдут банальные DOS и урезанная версия w2k без графического интефейса и много ещё чего (есть такая специально для АТС разработана). Надо ли говорить, что ни о каком GC на уровне ОС в них и речи не идёт.
MN>>2) как ни парадоксально звучит, но существующие реализации языков с GC усложняют процесс освобождение ресурсов.
SYG>Причина этой проблемы кроется совсем в другом. Когда Вы говорите "освобождение ресурсов", то имеете ввиду, что система со сборкой мусора работает поверх обычной древней системы и что Вы вынуждены пользоваться вот таким вот кодом: SYG>
SYG>f := FileOpen('a.txt');
SYG>
SYG>где функция FileOpen — это APIшная функция древней операционки не имеющей сборщика мусора. То есть проблема состоит во взаимодейсвии современных managed систем со старыми unmanaged системами...
Согласен с Кодт`ом, как в таких системах работать с COM портом, удалёнными серверами? Или если вам нужен пример более высокого уровня абстракции, пожалуйста: такой дорогой ресурс, как каналы АТС... интересно как будет работать такая система, где не будет явного вызова Close при завершении соединения... я думаю вы поняли о чём я.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[2]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, adb, Вы писали:
adb>А ведь GC используется скорее не ради удобства, а ради решения проблемы фрагментации. И как раз в сильно фрагментируемых системах GC намного эффективнее обычных куч (Это теоритически доказано!).
Это называется из пушки по воробьям. У нас есть большая числодробительная программа которая может считать несколько суток т.е. число циклов распределения-удаления памяти очень велико. Проблемма дефрагментации действително возникла, но если заюзать GC то был-бы вообще кошмар т.к. структураочень ветвистая (сеть) и обьектов около ~500к. В итоге я написал свой свой распределитель, так что и память очень плотно используется и дополнимтельных расходов 0 байт на обьект. Более того распределение и удаление обьекта было воистину быстрым. Потом были перегружены соотвествующие операторы new-delete и все стпло летать.
Вот куски кода показывающие "дешевизну" операций.
// удаление:void free_( void *p ) {
block *pb = (block*)p;
chunk *c = (chunk*)((size_t)p & (size_t)chunk_mask_);
pb->next = c->free;
c->free = pb;
c->used_n--;
}
// распределение:
block* alloc_() {
block *p = cur_->free;
if ( p ) {
cur_->free = p->next;
cur_->used_n++;
return p;
}
// в эту часть входим воистину редко
chunk *c = first_;
for ( ; c; c = c->next ) {
p = c->free;
if ( p ) {
cur_ = c;
cur_->free = p->next;
cur_->used_n++;
return p;
}
}
// а сюда еще реже
c = chunk_alloc_();
if ( c ) {
p = c->free;
cur_ = c;
cur_->free = p->next;
cur_->used_n++;
return p;
}
return (block*)Tr::out_of_mem();
}
Re[5]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Mr. None, Вы писали:
MN>Согласен с Кодт`ом, как в таких системах работать с COM портом, удалёнными серверами? Или если вам нужен пример более высокого уровня абстракции, пожалуйста: такой дорогой ресурс, как каналы АТС... интересно как будет работать такая система, где не будет явного вызова Close при завершении соединения... я думаю вы поняли о чём я.
Вот поэтому лучшие собаководы рекомендуют: после того, как вы закончили разговор по сотовому телефону, вне зависимости от гудков нажмите кнопку "повесить". Мало ли, этот маленький злодей не разорвёт соединение, и вы заплатите оператору за час бип-бип-бипа.
Перекуём баги на фичи!
Re[4]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Здравствуйте, Mr. None, Вы писали:
SYG>Это миф. Вот ссылка http://cern.ch/oberon.day/talks/ftkachov.pdf
Эта ссылка — такой же миф.
В файле приведен десяток ничего не доказывающих слайдов со взятыми неизвестно откуда цифрами.
Нужны исходники одного и второго тестов, только тогда можно эти результаты всерьез обсуждать.
... << RSDN@Home 1.1.3 stable >>
Re[4]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Это миф. Вот ссылка http://cern.ch/oberon.day/talks/ftkachov.pdf Физик-теоретик Федор Ткачев тестировал оберон-систему BlackBox на научных расчетах в области квантовой теории поля (согласитесь быстродействие там ОЧЕНЬ нужно) SYG>Результаты SYG>
SYG>BlackBox 1.4 Component Pascal 3.6 +/- 0.1 sec (With all safety check, with all debuging info)
SYG>MS Visual Studio 6.0 C++ 9.3 +/- 0.1 sec (debug)
SYG>MS Visual Studio 6.0 C++ 3.5 +/- 0.1 sec (Full speed optimization, O(10) slower compilation)
SYG>
SYG>В пределах точности измерений (+/- 0.1 sec) BlaclkBox 1.4 работает также быстро как и MS Visual Studio 6.0, причем в Component Pascal кроме сборщика мусора тормоза создавали еще и никогда не отключаемая проверка индексов массива и никогда не отключаемая проверка переполнения при арифметических операциях, по сути — это "дебажная версия".
Что-то я сомневаюсь, что сборка мусора вообще повлияла на измерения. Скорее всего, измерялось время собственно вычислений — а время остановки программы не учитывалось.
Более того, сама по себе процедура выделения памяти (даже не освобождения!) достаточно медленна. 10 миллионов вызовов (new int()) на моём компе занимают около 3 секунд.
Опять же, что именно делает та бенчмарка, о которой пишет Ткачёв? Занимается какой-то математикой. А кто сказал, что для математики нужно постоянно шуровать памятью? Тем более настораживает, что он постоянно пишет о фортране.
Вот если бы он с символьными вычислениями игрался — тут можно было бы задуматься; а так — это всего лишь демонстрация крутизны обероновского оптимизирующего компилятора.
Перекуём баги на фичи!
Re[5]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Кодт, Вы писали:
К>Вот если бы он с символьными вычислениями игрался — тут можно было бы задуматься; а так — это всего лишь демонстрация крутизны обероновского оптимизирующего компилятора.
Вы наверное будете удивлены, но по крайней мере когда я лично присутсвовал при другом его докладе (не в CERN-е, а в Москве), то он рассказывал именно о "символьных" вычислениях. Он вычислял Фейнмановские диаграммы (интегралы) теории возмущений, в огромных количествах. Кстати, хвастался тем что его программа считает эти интегралы в миллион раз быстрее чем Mathematica.
Re[5]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, eugals, Вы писали:
E>Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>>Здравствуйте, Mr. None, Вы писали:
SYG>>Это миф. Вот ссылка http://cern.ch/oberon.day/talks/ftkachov.pdf E>Эта ссылка — такой же миф. E>В файле приведен десяток ничего не доказывающих слайдов со взятыми неизвестно откуда цифрами. E>Нужны исходники одного и второго тестов, только тогда можно эти результаты всерьез обсуждать.
Так свяжитесь с Ткачевым, объясните ситуацию, потребуйте разъяснений...
Re[6]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Mr. None, Вы писали:
MN>2) как ни парадоксально звучит, но существующие реализации языков с GC усложняют процесс освобождение ресурсов. Постараюсь объяснить последний пункт, так как считаю его одним из самых серьёздных конструктивных просчётов. В C++ принята техника "выделение ресурса — есть инициализация", суть которой сводится к следующему — для управления некоторым ресурсом (файлом, дескриптором ядра ОС) пишется обёртка, которая в конструкторе выполняет открытие (захват) ресурса, а в деструкторе его закрытие освобождение. Если в некотрой локальной области вам нужен ресурс вы просто объявляете соответствующую статическую переменную, при выходе из этой области — нормально или вследствии исключения — вызывается деструктор и ресурс освобождается. Таким образом вам не надо следить за освобождением этого ресурса, не надо оборачивать всю область try-catch`ем
1) В C# есть конструкция using, которая не сильно сложнее процедурных скобок и повышае6т читабельность кода, потому что явно видно что по выходу из блока ресурс освобождается.
2) В MC++ и C++/CLI есть и автоматические деструкторы и GC, так что GC тут не при чем.
3) Автоматические деструкторы это compile-time технология, следовательно в компонентной среде без дополнительного шаманства не работает.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Mr. None, Вы писали:
MN>>2) как ни парадоксально звучит, но существующие реализации языков с GC усложняют процесс освобождение ресурсов. Постараюсь объяснить последний пункт, так как считаю его одним из самых серьёздных конструктивных просчётов. В C++ принята техника "выделение ресурса — есть инициализация", суть которой сводится к следующему — для управления некоторым ресурсом (файлом, дескриптором ядра ОС) пишется обёртка, которая в конструкторе выполняет открытие (захват) ресурса, а в деструкторе его закрытие освобождение. Если в некотрой локальной области вам нужен ресурс вы просто объявляете соответствующую статическую переменную, при выходе из этой области — нормально или вследствии исключения — вызывается деструктор и ресурс освобождается. Таким образом вам не надо следить за освобождением этого ресурса, не надо оборачивать всю область try-catch`ем
AVK>1) В C# есть конструкция using, которая не сильно сложнее процедурных скобок и повышае6т читабельность кода, потому что явно видно что по выходу из блока ресурс освобождается.
Я в курсе и выше я высказал своё отношение по этому поводу.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[6]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Mr. None, Вы писали:
MN>Извините не соглашусь — чрезмерное быстродействие там нафиг не нужно. Расчёты выполняются не в реальном времени. Вот пример систем, где быстродействие действительно критично: MN>слежение за спутником связи; MN>коммутация каналов на АТС; MN>контроль стыковки грузовика с космической станцией; MN>слежение за состоянием лифтов в здании и прочее и прочее...
Не путай критичность времени отклика и быстродействия. Для котроля стыковки к примеру быстродействие нужно просто никакое, все процессы там небыстрые, время стыковки даже на последних метрах измеряется минутами.
MN>Так вот открою вам тайну для управления такими системами даже операционки специальные пишутся, где всего по минимуму, главное чтобы реакция на внешний раздражитель была в пределах милисекунды.
Ага, все таки реакция, а не быстродействие. Вот тезис "системы с GC не пригодны для создания систем с гарантированным временем отклика" правильный.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Mr. None, Вы писали:
MN>>Я в курсе и выше я высказал своё отношение по этому поводу.
AVK>А по поводу второго пункта?
Ничего сказать не могу, потому что не было случая оценить MC++ полностью... помню только, что __gc классы в MC++ не могут иметь деструкторов (вроде так)
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[7]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Mr. None, Вы писали:
MN>Ничего сказать не могу, потому что не было случая оценить MC++ полностью... помню только, что __gc классы в MC++ не могут иметь деструкторов (вроде так)
Это не мешает сделать смартпоинтеры. Так что GC тут не при чем.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Mr. None, Вы писали:
MN>>Ничего сказать не могу, потому что не было случая оценить MC++ полностью... помню только, что __gc классы в MC++ не могут иметь деструкторов (вроде так)
AVK>Это не мешает сделать смартпоинтеры. Так что GC тут не при чем.
угу только это уже unmanaged код и .NET тут не причём получается — это pure c++
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[9]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Mr. None, Вы писали:
AVK>>>Это не мешает сделать смартпоинтеры. Так что GC тут не при чем.
MN>>угу только это уже unmanaged код
AVK>С какой стати?
Могу ошибаться, но в MC++ управляемыми являются только классы объявленные с добавлением ключевого слова __gc, их поведение в точночти соответсвует поведению классов из #C, исключением является следующее: если у такого класса определить дестрйктор, то его можно будет вызывать явно с помощью delete, но это не приведёт к очистке памяти — она очищается с помощью GC; неявного вызова деструктора при выходе из локальной области видимости не произойдёт. Если объявление __gc опущено, класс является обычным — неуправляемым классом C++ и правила вызова деструктора для него совпадает с обычными для C++.
Поправьте, если ошибаюсь.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[10]: Сборщик мусора необходим для компонентно ориентирова
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Mr. None, Вы писали:
AVK>>>Это не мешает сделать смартпоинтеры. Так что GC тут не при чем.
MN>>угу только это уже unmanaged код
AVK>С какой стати?
В том смысле, что умные-поинтеры — это абстракция Вашей программы. После компиляции их нету. А значит Ваш бинарник нельзя будет использовать совместно с бинарником написанном на другом языке программирования или даже на том же самом языке но без использования умных-указателей.
Re[3]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Mr. None, Вы писали:
MN>Здравствуйте, adb, Вы писали:
MN>Соглашусь, что GC вещь полезная, но многие существующие реализации языков с GC имеют ряд недостатков. Вот примеры: MN>1) быстродействие — ну это всем набило оскомину, по этому пункту даже спорить не буду, потому как в оправдание обычно приводят результаты искусственных тестов, которые не доказывают ничего; но вот когда быстродействие яаляется существенным ограничением, от GC обычно отказываются;
По поводу быстродействия. GC будет работать даже быстрее чем ручное освобождение памяти пр малом количестве живых объектов, т.к. вся работа сведется только к перемещению этих объектов при условии, что они в 0 поколении, а если во 2 то никаких действий окромя передвижки указателя кучи и не будет. А вот при большом их количестве заметен write barier и возможна реализация собственной кучи на валуе типах. При этом объекты более 80 кб никогда не перемещаются. MN>2) как ни парадоксально звучит, но существующие реализации языков с GC усложняют процесс освобождение ресурсов.
GC не усложняет, так же как и раньше ты должен следить за их освобождением. GC же подбирает твои огрехи, но вот момент финализации объектов неопределен. Здесь возможен контроль на этапе компиляции за объектами реализующими финализацию если какой либо объект не заключен в using или не вызван диспозе в области видимости то можно генерировать варнинги. Лишним это не будет.
... << RSDN@Home 1.1.3 stable >>
и солнце б утром не вставало, когда бы не было меня
Re[11]: Сборщик мусора необходим для компонентно ориентирова
Здравствуйте, Mr. None, Вы писали:
AVK>>С какой стати?
MN>Могу ошибаться, но в MC++ управляемыми являются только классы объявленные с добавлением ключевого слова __gc, их поведение в точночти соответсвует поведению классов из #C, исключением является следующее: если у такого класса определить дестрйктор, то его можно будет вызывать явно с помощью delete, но это не приведёт к очистке памяти — она очищается с помощью GC; неявного вызова деструктора при выходе из локальной области видимости не произойдёт. Если объявление __gc опущено, класс является обычным — неуправляемым классом C++ и правила вызова деструктора для него совпадает с обычными для C++.
Класс может и является неуправляемым, хотя что это такое я не знаю, а вот код будет оставаться управляемым по прежнему.
Здравствуйте, Serginio1, Вы писали:
S> По поводу быстродействия. GC будет работать даже быстрее чем ручное освобождение памяти пр малом количестве живых объектов, т.к. вся работа сведется только к перемещению этих объектов при условии, что они в 0 поколении, а если во 2 то никаких действий окромя передвижки указателя кучи и не будет. А вот при большом их количестве заметен write barier и возможна реализация собственной кучи на валуе типах. При этом объекты более 80 кб никогда не перемещаются. MN>>2) как ни парадоксально звучит, но существующие реализации языков с GC усложняют процесс освобождение ресурсов.
Чуть-чуть дополню.
Когда не надо удалять мусор, т.е. когда памяти в системе много, то прога с GC работает еще быстрее чем во вручную-кодированой-проге просто потому что во вручную-кодированой-проге Вы память освобождаете — а это отнимает время (выполнение инструкции delete занимает примерно столько же времени сколько и инструкции new).
Re[5]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Когда не надо удалять мусор, т.е. когда памяти в системе много, то прога с GC работает еще быстрее чем во вручную-кодированой-проге просто потому что во вручную-кодированой-проге Вы память освобождаете — а это отнимает время (выполнение инструкции delete занимает примерно столько же времени сколько и инструкции new).
Здесь многое зависит от менеджера памяти, но освобождение памяти более долгий процесс, при условии что нужен повторное ее использование.
на примере менеджера памяти Delphi http://www.rsdn.ru/article/Delphi/memmanager.xml
процесс удаления значительно сложнее выделения т.к. нужно объединять свободные куски памяти. При этом апишный
HeapFree раз в 10 медленне дельфевого Dispose
... << RSDN@Home 1.1.3 stable >>
и солнце б утром не вставало, когда бы не было меня
Re[5]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Чуть-чуть дополню.
SYG>Когда не надо удалять мусор, т.е. когда памяти в системе много, то прога с GC работает еще быстрее чем во вручную-кодированой-проге просто потому что во вручную-кодированой-проге Вы память освобождаете — а это отнимает время (выполнение инструкции delete занимает примерно столько же времени сколько и инструкции new).
Ну это тоже не обязательно, всё зависит от того, как оптимизирован менеджер памяти. Некоторые реализации при обработке delete не вовзращают память системе, а запоминают во внутреннем списке, чтобы при первой необходимости снова вернуть её программе. Тем самым достигается оптимизация и освобождения, и повторного выделения. По сути тоже самое делает и GC...
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[6]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, adb, Вы писали:
adb>Это разные равноценные подходы. Не более. Только один предлагает явно высвобождать ресурсы, а второй неявно. При этом, как я уже сказал, во втором случае мы платим прозрачностью кода за удобство написания.
Тут уже был флейм на тему C vs С++, где одной из ключевых тем было как раз то, что освобождение ресурсов в явном виде преподносилось как плюс. Долго переубеждали и доказывали, что это всё-таки (в большинстве случаев) минус, так как основное в программе — это её бизнес-логика, а детали работы — это визуальный шум, который по возможности желательно скрыть... И вот опять 25 только теперь с блоком finally.
Блок finally, при отсутсвии деструкторов — явный шаг назад, по сравнению с C++ То есть наверное есть ситуации, где явное освобождение в finally — предпочтительнее скрытого освобождения в деструкторе, но это скорее исключения, а не правило...
Похоже что проблема не в концепции Garbage Collector, а в желании Microsoft отнять рынок (или хотя бы его часть) у Java, для чего в C# и .NET многое было передрано из Java механически и бездумно.
Деструкторы для размерных типов были бы одним из возможных решений.
Re[5]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Чуть-чуть дополню.
SYG>Когда не надо удалять мусор, т.е. когда памяти в системе много, то прога с GC работает еще быстрее чем во вручную-кодированой-проге просто потому что во вручную-кодированой-проге Вы память освобождаете — а это отнимает время (выполнение инструкции delete занимает примерно столько же времени сколько и инструкции new).
Зато в ручной проге все работает гладко и равномерно без сюрпризов. А в GC-шной котороая которая эксплуатируется в интеснсивном режиме (например интенсивный гейм) сборка мусора все откладвается, откладывается, откладывается и когда наконец все 512 мегофф исчерпаны. Программа говорит геймеру (в самый интересный момент) СТОП и начинает сборку мусора. Что приводит к припадку ярости, разрушениею монитора кувалдой и т.д. и т.п.
Re[6]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Здравствуйте, Кодт, Вы писали:
К>>Вот если бы он с символьными вычислениями игрался — тут можно было бы задуматься; а так — это всего лишь демонстрация крутизны обероновского оптимизирующего компилятора.
SYG>Вы наверное будете удивлены, но по крайней мере когда я лично присутсвовал при другом его докладе (не в CERN-е, а в Москве), то он рассказывал именно о "символьных" вычислениях. Он вычислял Фейнмановские диаграммы (интегралы) теории возмущений, в огромных количествах. Кстати, хвастался тем что его программа считает эти интегралы в миллион раз быстрее чем Mathematica.
Что, однако не мешает ей предварительно или крупными блоками резервировать память, а потом с ней работать... Тут и правда нужен исходный код...
Re[6]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, S.Yu.Gubanov, Вы писали:
S> Здесь многое зависит от менеджера памяти, но освобождение памяти более долгий процесс, при условии что нужен повторное ее использование. S> на примере менеджера памяти Delphi S>http://www.rsdn.ru/article/Delphi/memmanager.xml
S> процесс удаления значительно сложнее выделения т.к. нужно объединять свободные куски памяти. При этом апишный S> HeapFree раз в 10 медленне дельфевого Dispose
Прелесть ручного распределения в том что критический участок всегда можно соптимизировать. куча — действительно медленная штука из-за своей универсальноссти. Для конкретной ситуации можно написать свой заоптимизированный распределитель и ускорить так что любому ГЦ даже и не снилось.
Приведу еще раз те фрагменты кода котороые показывают дешевизну операций (ручная оптимизация)
// удаление:void free_( void *p ) {
block *pb = (block*)p;
chunk *c = (chunk*)((size_t)p & (size_t)chunk_mask_);
pb->next = c->free;
c->free = pb;
c->used_n--;
}
// распределение:
block* alloc_() {
block *p = cur_->free;
if ( p ) {
cur_->free = p->next;
cur_->used_n++;
return p;
}
// в эту часть входим воистину редко
// .......
}
Более того этот распределитель эксплуатируется фактически в стрессовых условиях, непрерывная круглосуточная работа и большие обьемы выделяемой удаляемой памяти до 500к обьектов (~200Мб)
Любой ГЦ бы просто здох.
Re[4]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
MN>>2) как ни парадоксально звучит, но существующие реализации языков с GC усложняют процесс освобождение ресурсов.
SYG>Причина этой проблемы кроется совсем в другом. Когда Вы говорите "освобождение ресурсов", то имеете ввиду, что система со сборкой мусора работает поверх обычной древней системы и что Вы вынуждены пользоваться вот таким вот кодом: SYG>
SYG>f := FileOpen('a.txt');
SYG>
SYG>где функция FileOpen — это APIшная функция древней операционки не имеющей сборщика мусора. То есть проблема состоит во взаимодейсвии современных managed систем со старыми unmanaged системами. Такая проблема есть в Java так как Java, являясь виртуальной машиной, всегда работает поверх какой-то другой реальной машины. В Оберон-системах такой проблемы нет потому что там вся операционка написана от начала и до конца в объектно ориентированном стиле учитывающем сборщик мусора (сборщик мусора интегрирован в саму ОСь). Там в самой операционке просто нету таких опасных низкоуровневых функций как OpenFile(), CloseFile(), а значит и нету проблем связанных с Вашим "освобождением ресурсов".
Это позволит нам обойтись без явных вызовов CloseFile(), но, насколько я понял, файл будет закрыт так же "своевременно", как если бы мы поместили CloseFile() в finalize().
SYG>Я уже писал об этом: SYG>http://www.rsdn.ru/Forum/Message.aspx?mid=725451&only=1
SYG>>Это, мягко говоря, немного устаревший способ работы с файлами. Всвязи с появлением ООП, люди уже более десятка лет с файлами работают на более высоком уровне абстракции. Могу вкратце описать как это делается в системе BlackBox от Oberon Microsystems. В этой системе для этой цели используется паттерн проектирования под названием "Carrier-Rider-Mapper". Carrier — это персистентный объект содержащий внутри себя какие-либо данные ....
[поскипан большой объем текста]
Если я верно понял, здесь ты описал классическую схему Файл — Дескрипторы(хэндлы) — Средства форматированного ввода/вывода. И "более выскокий уровень абстракции" заключается в том, что вместо подсчета ссылок Дескрипторов на Файл используется GC. Я не могу классифицировать это изменение по шкале хорошо/плохо, просто предлагаю употреблять поменьше громких слов
Тут рядом топик Насколько быстр HeapAlloc?
Я там про это и веду речь. Но обычно то кучи общие, хотя все узкие места можно (и нужно) оптимизировать.
Но GC при малом количестве живых объектов будет в любом случае самым оптимальным
при этом учитывая интервалы между сбором мусора которые могут быть весьмя продолжительными.
... << RSDN@Home 1.1.3 stable >>
и солнце б утром не вставало, когда бы не было меня
Re[5]: Сборщик мусора необходим для компонентно ориентирован
Здравствуйте, S.Yu.Gubanov, Вы писали:
SYG>Когда не надо удалять мусор, т.е. когда памяти в системе много, то прога с GC работает еще быстрее чем во вручную-кодированой-проге просто потому что во вручную-кодированой-проге Вы память освобождаете — а это отнимает время (выполнение инструкции delete занимает примерно столько же времени сколько и инструкции new).
Шито по воде белыми вилами. Это все очень сильно зависит от менеджера памяти.
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Уж послали в "сад", так я и пришёл.
SYG>Сборщик мусора необходим для компонентно ориентированного программирования.
SYG>Вот, вынес в отдельную ветку тему о необходимости сборщика мусора в компонентно ориентированных системах. Более десяти лет назад люди поняли, что полноценные компонентные (модульные) системы невозможны без наличия единого сборщика мусора.
Так... медленнно, по буквам. Компонетная система начинается с определения понятия "компонент", и "среда работы компонента". Она может быть как с GC, так и без GC.
Да, невозможно зафиксировать момент удаления объекта, если он — разделяемый и циклы существования пользователей никак между собой не связаны (к примеру — синглтон). Модуль — разделяемая сущность, поэтому для неё необходим или счётчик ссылок, или "подметатель". Счётчик ссылок в данном случае — дешевле и очевидней, поскольку в таком случае можно отслеживать только моменты создания/удаления объектов, а не весь периметр ссылок на них. Да и сама структура ссылок может быть приведена к простейшей: указателю на область памяти. Причём тут обязательность GC?
Так что, ИМХО, исходный тезис неправомерен.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Модуль — разделяемая сущность, поэтому для неё необходим или счётчик ссылок, или "подметатель".
...
ГВ>Так что, ИМХО, исходный тезис неправомерен.
Вы перепутали модули с объектами. Модули создают объекты и отдают эти объекты другим модулям и т.д. Уборка мусора нужна для объектов. А что касается модулей, то они грузятся в систему загрузчиком, динамически линкуются и остаются в памяти пока их явно не выгрузят.