Чтобы добавлять сообщения и комментарии, .

@OCTAGRAM:
OCTAGRAM

Почитал Interfacing with the XPCOM cycle collector, посмотрел красивые картинки и подумал, что хотя в идеале лучше иметь царя в голове, который и в этой голове, и в коде порядок наведёт на радость пользователю, не взбешённому фризами от свопов от сборок мусора, но подобным инструментом можно портировать код, в который трассирующая сборка мусора въелась так, что уже не отдраить. Только ещё небольшое дополнение к этой схеме я бы сделал. В норме далеко не любые объекты в строго типизированной системе вообще способны образовать цикл, а если способны, то не любыми своими полями, и это можно отследить по допустимым типам полей, некисло усекая анализируемый подграф. Эту схему чаще всего ломал бы базовый тип (java.lang.Object в Java), так как он-то действительно нередок как универсальное хранилище значений и потенциально может использоваться для образования циклов, но дженерики в Java 6 уменьшают количество мест, где такой универсальный тип может встретиться.
XPCOM для этого плохо подходит, поскольку на один объект может ссылаться несколько двоично отличающихся указателей, и сборщику циклов приходится приходится делать QueryInterface для каждой встреченной ссылки, чтобы привести их к одному знаменателю. Также в XPCOM любой объект потенциально поддерживает любой интерфейс, и статический анализ (или анализ во время инициализации класса) невозможен. Зато возможен в SOM, если модифицировать эмиттеры. Даже в немодифицированном SOM можно открыть хранилище интерфейсов, и у класса InterfaceDef получить свойство InstanceData в формате CORBA TypeCode с TypeCode_kind = tk_struct, и по ней прочесать поля, другое дело, что хранилище интерфейсов не гарантированно синхронизировано с реальным кодом, в отличие от эмиттера, который бы вшивал всегда актуальное описание в служебный код реализации класса. Для тяжёлых случаев можно-таки реализовать аналог nsICycleCollectionParticipant. Лучше всего при инициализации новых классов строить орграф, находить в нём сильные компоненты связности, схлопывать их в один узел, а оставшийся орграф без контуров сортировать по уровням, так что если при попытке добавления нового класса приходится опустить отсортированные ранее, то при наличии вновь появившегося потенциального цикла это сделать не удастся, и цикл будет инкрементально обнаружен. Сборщик цикла может просто сравнивать идентификатор компоненты сильной связности своего класса с идентификаторами у сначала формальных, потом реальных типов полей, не нужно потом обходить их родительские классы. Это позволит впоследствии максимально сузить круг поиска при сборке цикла, по возможности не давая этой отраве выплеснуться наружу, а если уж выплеснулось, то изолировать токсичные выбросы друг от друга.
Сильно завозить эвристику тоже не хочется, а начинать или не начинать сборку циклов — это уже эвристика. Вместо этого, руководствуясь принципом «сначала сделать, чтоб работало, потом сделать, чтоб работало быстро», можно предложить такой способ переноса с Java, когда вообще каждая операция декремента, не обнулившая счётчик ссылок, вызывает сборщик цикла, ограниченный вычисленной компонентой связности для подозрительного объекта. Я бы не удивился, если такая суровая реализация работала даже быстрее, чем все эти свопы и фризы в хвалёном трассирующем сборщике. А если надо, чтобы работало ещё быстрее, — извольте наводить порядок в голове и коде. Кстати, я посмотрел, в Javolution самый обычный счётчик ссылок, и ничего, несколько проектов им портировано. Выходит, по силам Java-разработчикам навести у себя порядок.

@OCTAGRAM:
OCTAGRAM

Заглянул в список «Кто в онлайне» и не увидел никого с сайта, хотя я интегрировал их. Решил посмотреть, а что там с сайтом. Ну конечно, он опять не открывается! Правильно, а зачем обслуживать посетителей, когда есть другие, более интересные дела, такие, как сборка мусора? javaw.exe ест весь CPU, а страница так и не открылась. Придётся всё же заняться переносом вики на Аду. Достало!

@OCTAGRAM:
OCTAGRAM

Как Composer на 70% ускорили
Before: Memory usage: 135.4MB (peak: 527.71MB), time: 119.82s
After: Memory usage: 134.89MB (peak: 391.28MB), time: 11.26s

Before: Memory usage: 163.66MB (peak: 403.82MB), time: 246.25s
After: Memory usage: 163.34MB (peak: 350.36MB), time: 99.55s

Вспоминается #2822358/142:
ну я не знаю, если ты умеешь замечать фризы порядка сотой доли секунды; ну ладно, в плохом случае у я видел было 0.2с, но это было когда висела живая стуктура (в языке без GC она бы висела такаяже) на пару гигов в памяти, то я тебя боюь.
Насколько я понимаю, RC в PHP работает всё равно, ну правда, из–за того, что такое поведение сейчас не штатное в PHP, разработчики к нему не готовились, могут быть кольца, но как видно, ТАААААКИХ проблем, как GC, они не создают. Но те несчастные, кому не повезло заполучить в свой ЯП сборку мусора безальтернативно, будут и дальше ничего не замечать, и продолжать свою пропаганду, и куча кодеров продолжат писать свой код так, что мой 2Гб ноут на ровном месте раз в минуту переклинивает на сборку мусора. А, может, дело не в RAM, а в том, что количество ядер меньше количества одновременно запущенных использующих сборку мусора программ. Если б было больше, ну и использовали каждая по 100% ядра, собирая мусор с перерывами на своп, и не тормозили друг друга. Где ж тут напасёшься RAM и ядер на это увлекательное занятие.

@OCTAGRAM:
OCTAGRAM

Мощный разнос сборки мусора
> We feel so strongly about ARC being the right approach to memory management that we have decided to deprecate Garbage Collection in OSX. – Session 101, Platforms Kickoff, 2012, ~01:13:50
The part that the transcript doesn’t tell you is that the audience broke out into applause upon hearing this statement. Okay, now this is really freaking weird. You mean to tell me that there’s a room full of developers applauding the return to the pre-garbage collection chaos? Just imagine the pin drop if Matz announced the deprecation of GC at RubyConf. And these guys are happy about it? Weirdos.
Я бы хотел, чтобы не только приложения для мобильных устройств, которых у меня не было и нет, берегли память и производительность (не считая J2ME на бывшем Philips 9@9u, который, впрочем, не берёг ни того, ни другого, и работал еле как), но и чтоб на моём не самом плохом ноуте никакая программа из 20 запущенных не думала, что 4Gb — это всё для неё, и не вгоняла компьютер в тормоза, подобные тем, которые я видел, когда установил Windows XP на AMD K5.

Вообще, замечательно, что Apple выпустили ARC в общий доступ. Потому что сколько крестоносцы ни молились на шаблоны и метапрограммирование, а всё ж я не видел, чтоб этими шаблонами можно было автоматически об–RC'ить классы со всеми аргументами каждого их метода так же удобно, как это у интерфейсов в Delphi и ARC в LLVM.

Totally unprompted, the developers bring up garbage collection as the biggest bottleneck.
Карфаген должен быть разрушен

@OCTAGRAM:
OCTAGRAM

Есть у меня одно соображение насчёт подсчёта ссылок вместо сборки мусора, которое заключается, помимо длинных пауз и больших изначальных выделений памяти, в том, что если клиент каким–то образом может точно знать, что он единственный владелец структуры данных, то он может изменить её, а при сборке мусора на структуру может ссылаться невесть сколько желающих, и, чтобы не было сюрпризов, может требоваться делать глубокое копирование, и за счёт отсутствия глубоких копирований подсчёт ссылок может и выруливать. Однако, чтобы это было так, нужно, чтобы вместо сумбурных представлений типа «вот, если мы убедились, что мы единственный владелец, мы можем внести изменения прямо на месте, а если не совсем единственный, то оптимальным образом скопировать узлы на пути от корня к потомку, а соседние узлы оставить общие» иметь некое более формализованное представление, которое можно закодировать или хотя бы представить. Потому что в моих CVariants для Делфей ( bitbucket.org ), например, счётчик ссылок, но глубокое копирование делать всё равно надо, потому что я в требуемые сроки логику разработать и воплотить в жизнь не смог. А зря. Дельты бы значительно ускорились (в контексте задачи приложение на терминале, который, как правило, на GPRS, описывает своё состояние в виде большой структуры и передаёт на сервер, а для экономии трафика шлются только дельты).

Так вот, попробуем набросать:
Итак, для начала надо отбросить двоичную логику константа/неконстанта, мутируемый/немутируемый. Эта путаница идёт, мне кажется, из языков программирования. То есть, если у нас есть X : constant Integer := 3; в синтаксисе Ada, или const X: Integer = 3; в синтаксисе Delphi или const int X = 3; в синтаксисе C, то это сравнительно настоящая константа. Её неизменность гарантируется языком программирования, если не пытаться обхитрить его cast'ом, а ещё может гарантироваться OS и CPU защитой от записи в соответствующие страницы памяти. А кроме таких настоящих констант есть так называемые указатели на константы (access constant в синтаксисе Ада), которые на самом деле могут быть не указатели на константы, а указатели в режиме только–чтение, что не то же самое, что указатель на константу. А такой вещи, как указатель на константу, на самом деле нет, и я сейчас критикую не языки программирования, а ту картину мира, которая непроизвольно складывается, если ими пользоваться. Пока не поймёшь, что нам может зачем–то понадобиться не 2 типа сущностей, а 3, сложно продвинуться. Итак, на мой взгляд, нам нужны:
1. Ссылки (умные указатели, итераторы) в режиме чтение–запись, которые знают, где корень той структуры, которую они представляют, и каков точный путь от этого корня к тому узлу, на который эта ссылка. Кроме корня, есть ещё один главный объект (переменная), который олицетворяет структуру таким образом, что изменения, производимые над структурой, должны быть видны только тем клиентам, которые используют ссылки с тем же главным объектом. Корень может быть общим у нескольких главных объектов до первого изменения.
2. Ссылки в режиме только–чтение на потенциально изменчивые структуры. Они нужны, чтобы соответствовать формальным требованиям алгоритмов, но было бы ошибкой выдавать налево и направо гарантии неизменности содержимого.
3. Константы, представляющие структуры, которые гарантированно не изменятся. Ссылки на константы не знают про корень структуры, которой они принадлежат, в противном случае это были бы ссылки второго типа. Константы–списки и константы–словари ссылаются на другие константы, у которых уже нельзя узнать родителя.

@ndtimofeev:
ndtimofeev

А есть сканирующие алгоритмы сборки мусора для которых не нужна карта корневых ссылок?

@4DA:
4DA

В каких языках программирования есть реализация realtime gc?

@az09:
az09

В пять (5 блджад!) раз больше необходимого требуется памяти для комфортного сбора мусора!11 До чего же мы^wвы докатились, а, погромисты!?

@borman:
borman

I mean, in iOS world, we don’t believe in garbage collectors, and we think the Android guys are nuts. I suspect that the Android guys think the iOS guys are nuts for manual memory management. But you know what the two, cutthroat opposition camps can agree about? The JavaScript folks are really nuts.

@segfault:
segfault

Продолжнаю тему объектов А и Б из #2478911
Вот есть у меня реализация объекта А, этот объект умеет делать disconnect
при дисконнекте финализирует всех своих детей вот так

  disconnect conn = modifyMVar_ (scDatabase conn) $ \c -> case c of
    Nothing -> return Nothing
    Just (con) -> do
      closeAllChildren (scStatements conn)
      res <- SD.close con 
      case res of
        Left err  -> throwErrMsg con $ show err 
        Right () -> return Nothing

сдесь choseAllChildren выглядит так

closeAllChildren :: (Statement stmt) => (ChildList stmt) -> IO () 
closeAllChildren mcl = modifyMVar_ mcl $ \ls -> do 
  mapM_ closefunc ls 
  return ls 
    where closefunc child =
              do c <- deRefWeak child
                 case c of 
                   Nothing -> return () 
                   Just x -> finish x

Так же при добавлении чайлда (объекта Б) добавляется финализатор, который финализирует потомка если того решил удалить сборщик мусора

childFinalizer :: (Statement stmt) => stmt -> ChildList stmt -> IO ()
childFinalizer stmt mcl = do
  putStrLn "Finalizer called, performing finish"
  finish stmt                   -- make sure the statement is finished
  c <- isEmptyMVar mcl
  case c of
    True   -> return ()
    False  -> modifyMVar_ mcl (filterM filterfunc)

  where filterfunc c = do
          dc <- deRefWeak c
          case dc of
            Nothing -> return False
            Just _ -> return True

Как видим, финализатор делает потомку finish, а потом удаляет себя (вернее все пустые ссылки) из списка чайлдов

Теперь вот такой код

perf c = do 
  runRaw c "create table integers (val)"
  s <- prepare c "select * from integers"
  return () 

main = do 
  c <- connectSqlite3 ":memory:"
  perf c
  performGC
  disconnect c

Вызывает вот такую ошибку

hhh: SqlError {seErrorCode = "ErrorBusy", seErrorMsg = "unable to close due to unfinalized statements or unfinished backups"}
Finalizer called, performing finish

если убрать performGC то все работает. Я делаю такой вывод: когда сборщик мусора срабатывает, то сначала ссылки в списке чайлдов становятся пустыми (изза чего мы не делаем finish объекту в списке, так как ссылка уже пустая), потом происходит все остальное (закрытие соединения с ошибкой) а затем вызывается финализатор, уже после закрытия соединения.
Теперь вопрос, как сделать так, чтобы closeAllChilds дождалась отработки всех финализаторов объектов Б?

@folex:
folex

Поцоны, кто знает, как в sgen посмотреть трейс или логи какие-нибудь? Как вообще посмотреть, чо и когда он стирает?

@trapdoor:
trapdoor

окак! hackage.haskell.org

@melkor217:
melkor217

одному моему знакомому нужно океево настроить GC для работы на больших объемах памяти. не подкинете годных статей на эту тему?

@4DA:
4DA

Раз уж на жуйце неделя GC, то реквестирую советов:
Допустим, я реализую. Язык с GC.
Что лучше:
1. Пожрать говна^W^W сделать GC самому (по наитию) и потом ужаснуться от результата и перейти к п. 2.
2. Почитать хороших вайтпапиров и реализовать какой-нибудь из описанных алгоритмов.

?

@dr-Chaos:
dr-Chaos

На кывте народ подкинул забавную ссылку про проблемы GC Java и .Net dev.by , т.е. при определённых достаточно простых условиях можно нарваться на проблемы.
Собственно вброс^W вопрос как с этим у Хаскела? Это просто решено по другому или GC иначе работает?

@lovesan:
lovesan

[ Про управление памятью, ответ на #1762666/9 ]

Полюбому — одни неосиляторы вокруг. В майкрософте неосиляторы на какой-то хуй в COM ввели всю эту поебень с управлением памятью, в GObject там что-то, про извращения из буста и Qt я даже не говорю. А самые самые неосилившие неосиляторы придумали такую хрень как сборщики мусора — пиздец ведь, да? Ну надо же какие неосиляторы то блять, вообще нихуя не осилили — дрочат там какие-то оптимизирующие эвристики автоматического управления памятью, выдумывают алгоритмы для автоматизированного менеджмента ресурсов в многопоточной среде, а какие-то malloc/new/free/delete в нужных местах расставлять — не осилили. Вот лохи то тупые, ебта!



Блядь, когда у тебя программа состоит из чего-то крупнее трех статических массивов с интами и двух динамических с флоатами, которые тебе надо перемножить и вывести на stdout чтобы сдать лабораторку в твоем ПТУ — хуюшки ты уследишь за всем ручками. Это я еще не говорю про коллбеки-интерфейсы, про интеграцию с чужим кодом, про интеграцию с разными языками программирования, с разными рантаймами и прочее. И не надо пиздеть что это все от неосиляторства. "Неосиляторство" это отмазка малолетних долбоебов, даже на тех самых C++ то толком не писавших.

@lovesan:
lovesan

вынесу из комментов: juick.com

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

GC как раз очень правильная адаптивная(против halting problem не попрешь) методика, и в 99.99% случаев является лучшим выбором. Но, естественно, правильный, нормальный двигающий GC, которому компилятор помогает всякими там escape analysis.

А GC — если причина тормозов, то по сравнению с чем? С malloc/new? Ну это не смешно даже — последние то это вообще пиздец. Причины тормозов программ на высокоуровневых языках совершенно не в GC.

Причины либо

1) В слишком динамичных рантаймах, а значит в куче метаданных, связанных с объектами, и значит, в постоянном боксинге, промахах кеша и прочем подобном. (примеры — smalltalk, scheme)

2) В кривых компиляторах или рантаймах, написанных криворукими дебилами(python, ruby)

3) В неуемном использовании абстракций, такого уровня, который на языках типа Си и C++ без разрывания жопы пополам просто не достичь. (это основная причина тормозов кода на java и .net)

@lovesan:
lovesan

Первый GC для .NET был написан на Лиспе.
И потом переведен в C++ автоматическим source-to-source транслятором.
channel9.msdn.com

Его разработчик, Patrick Dussud, являвшийся главным инженером по части GC в .Net(и являющийся теперь, как MS пишет — lead architect for the .NET Common Language Runtime, the chief architect for the .NET Framework, and is a member of the Window Core Architecture team) — раньше работал в Texas Instruments и других подобных компаниях(например Lucid Inc.) и писал там в частности на ZetaLisp(диалект для Lisp-машин, предшественник Common Lisp) и на собственно самом Common Lisp.
microsoft.com

Так то!

@gli:
gli

еще одна книжка в список на "почитать когда-нибудь": "The Garbage Collection Handbook: The Art of Automatic Memory Management", 2012
amazon.com

@bioh:
bioh

memorymanagement.org — Welcome to The Memory Management Reference! This is a resource for programmers and computer scientists interested in memory management and garbage collection.
Сайт уже давно не обновляется, но содержит отличный сборник статей по данной тематике (есть ссылки на полный текст, но далеко не все они живы), а также ссылки на другие ресурсы соответствующей тематики.
Было бы здорово "оживить" такой сайт.

@avbelyy:
avbelyy

Интересно, в GTK/GObject есть автоматический сборщик мусора? Если нет, разработка GTK-приложения на Си со временем превратится в жуткий п****ц...

@Kim:
Kim

В gprolog нет сборщика мусора. Для управления памятью в WAM используются инструкции allocate/1 и deallocate/0, что для меня достаточно неожиданно.

@lovesan:
lovesan

Вот собрал несколько умных книжек на тему алгоритмов сборки мусора(garbage collection).

Paul R. Wilson, "Uniprocessor Garbage Collection Techniques"
rghost.ru

Richard Jones, "Garbage Collection Algorithms For Automatic Dynamic Memory Management" (мегакнижка, но качество скана немного хромает)
rghost.ru

Ну и вот, не совсем конкретно по теме, но там есть в т.ч. и про рантаймы языков с GC.
Ахо, Лам, Сети, Ульман, "Компиляторы: принципы, технологии и инструментарий" (рус., 2е издание, 2008)
rghost.ru

@sai:
sai

Няшечки, подскажите где почитать про сборку мусора, завтра зачёт сдавать, а я знаю всё только в общих чертах

@borman:
borman

Жуйк, подскажи, а то я что-то не понимаю. Скажем, есть у нас некоторая программа на ML, собранная через MLTon. (Возможно, это верно и для Haskell/GHC), не знаю. Так вот, для выделения памяти она резервирует сразу большой пул (50% RAM по умолчанию) и в нем живет. А теперь представим себе, что мы держим некоторую инфраструктуру из кучи таких приложений. Ну штук 10, например. И мне что-то кажется, что когда каждая возьмет себе пул, им всем будет тесновато. А теперь вопрос: прав ли я? И если прав, есть ли способ решения проблемы?

@lovesan:
lovesan

Сравнил производительность сборщика мусора из SBCL и boost::shared_ptr

Подробное описание теста, с полным кодом программ, дизассемблами и "нотариально заверенными скриншотами":
love5an.livejournal.com

Результаты для "умных указателей" вышли печальные — они тормозят. Причем тормозят просто пиздец.

@Balancer:
Balancer

img341.imageshack.us

@rion:
rion

а что сборщик мусора в бедоне вообще никак не умеет рекурсивные ссылки обрабатывать? :-( аля если два объекта ссылаются друг на друга и больше нет каких-либо ссылок на них, то они всё равно никогда не будут удалены?

@diseaz:
diseaz

Concurrent Garbage Collection <wknight8111.blogspot.com> ссылки на несколько статей о сборщиках мусора.

@diseaz:
diseaz

Very Concurrent Mark-&-Sweep Garbage Collection without Fine-Grain Synchronization <doc.cat-v.org>