Сборщик мусора vs Умный указатель
Так вот, недавно в голову пришла идея - реализовать такой сборщик. Создаем класс, очень схожий с shared_ptr, но с небольшими отличиями - наш класс никогда не будет уничтожать контролируемый им объект. Запускаем поток (далее - Сборщик), который будет заниматься сборкой мусора. Имеется контейнер, содержащий ссылки на все выделенные объекты.
Каждый раз при создании объекта помещаем в контейнер наш аналог shared_ptr.
Поток Сборщика срабатывает только тогда, когда машине "нечем заняться", либо при недостатке памяти в момент очередного создания объекта.
Сборщик анализирует контейнер на наличие неиспользуемых объектов и уничтожает их. Для ускорения поиска таких объектов контейнер проиндексируем по признаку отсутствия ссылок, этот признак будет выставляться нашим аналогом shared_ptr.
Как известно, в многопотоковых приложениях операция выделения памяти должна блокировать некий мьютекс на выделение места в куче (heap). Так вот, можно не создавать отдельный мютекс на блокировку контейнера выделенных объектов - вставка объекта в этот контейнер может происходить одновременно с выделением места в куче. Что касается уничтожения объектов - возникает еще одна экономия: не нужно блокировать кучу при каждом уничтожении объекта, поскольку этим занимается Сборщик, он может за один сеанс уничтожить много объектов.
Мне кажется, такая концепция в многопотоковых приложениях, часто обращающихся к куче, будет работать лучше, чем shared_ptr/scoped_ptr/auto_ptr и др...
Хотелось бы услышать мнение знатоков.
http://forum.codenet.ru/showthread.php?p=136960
Дело в том, что функция сборщика не просто удалить память от неиспользуемых объектов, но и оптимизировать после этого расположение используемых объектов, т.е. провести дефрагментацию. И IMHO это его основное достоинство. Но это достоинство предполагает наличие run-time инф. о типах, возможность сериализации.
Удалять объекты лучше все же сразу после использования.
От "забывчивости" помогают умные указатели и их вполне достаточно.
Для продуктивности в многопоточных приложениях можно придумать множество решений. Например, предоставить каждому потоку свою собственную область памяти для кучи.
А вот дефрагментация - серьезная проблема, ососбенно при жестком лимите памяти. Решения конечно тоже есть, например, по-разному выделять память под большие и маленькие объекты.
---
А вот дефрагментация - серьезная проблема, ососбенно при жестком лимите памяти. Решения конечно тоже есть, например, по-разному выделять память под большие и маленькие объекты.
Дефрагментация, я считаю - это долго. Иногда неприемлемо. Сериализация тоже. Насчет указанных "решений" - ты, наверное, имел в виду low fragmentation heap -это удачное решение, позволяющее избежать фрагментации (не совсем, конечно, но примерно так...). К тому же, как реализована куча - обычная это куча или LFH - это концепция, независимая от умных указателей или сборщика мусора - и тот и другой можно реализовать и на той, и на другой куче.
Отчасти согласен, отчасти нет.
Почему не согласен - см. первоначальный пост, там я указал преимущества отложенного уничтожения объектов.
Согласен в том, что иногда объект должен сразу освобождать какие-то ресурсы, особенно не связанные с памятью, сразу после того, как перестает использоваться, а не тогда, когда вздумается сбощику мусора. К примеру, поверхности DirectDraw или что-то вроде того - короче, "дорогие" ресурсы.
.NET - платформа, насколько мне известно, с этой целью вместо понятия деструктора вводит два понятия - некий "клинапер", освобождающий эти дорогие ресурсы, и собственно деструктор, освобождающий "недорогие" ресурсы и связанные, подчиненные и т. п. объекты.
В общем, все правильно, но если честно, я писал первоначальный пост немного в контексте конкретной проблемы - многопоточные приложения часто выделяющие/освобождающие память, в которых потоки сильно взаимосвязаны - имеется множество "общих", "межпотоковых" объектов. Тут сложно выдать каждому потоку свою кучу.
Итог сему посту таков.
Дефрагментацию нафиг - используем LFH.
Видимо, придется изобретать отдельный "клинер" каждому объекту, и отдельно - деструктор.
Таким образом избежим частых блокировок кучи и сэкономим время в моменты загруженности приложения.
Конечно, все это верно в "контексте конкретной проблемы".
А эту проблему можно решить, но другими способами - в моем приложении я помещаю запросы на выполнение заданий во вторичную очередь, как только первичная очередь (уже исполняющихся заданий) опустошится, вторичную очередь запускаем на исполнение, т. е. переносим ее в первичную. Это, конечно, частное решение, но уверен - в ряде других случаев решение можно по этому подобию придумать.