Фрагментация кучи больших объектов: есть ли у нее решение для CLR? - PullRequest
7 голосов
/ 09 марта 2011

Если ваше приложение таково, что оно должно выполнять много операций выделения / перераспределения объектов большого размера (> 85000 байт), это в конечном итоге приведет к фрагментации памяти, и ваше приложение выдаст исключение Out of memory.

Есть ли какое-нибудь решение этой проблемы или это ограничение управления памятью CLR?

Ответы [ 6 ]

7 голосов
/ 09 марта 2011

К сожалению, вся информация, которую я когда-либо видел, предлагает только управлять факторами риска самостоятельно: повторно использовать большие объекты, размещать их в начале, убедиться, что они имеют размеры, кратные друг другу, использовать альтернативные структуры данных (списки , деревья) вместо массивов. Это просто дало мне другую идею создания не фрагментированного списка, который вместо одного большого массива разделяется на меньшие. Массивы / списки, кажется, являются наиболее частыми виновниками IME.

Вот статья в журнале MSDN: http://msdn.microsoft.com/en-us/magazine/cc534993.aspx, но в этом не так много полезного.

3 голосов
/ 13 марта 2011

Особенность больших объектов в сборщике мусора в CLR заключается в том, что они управляются в другой куче. Сборщик мусора использует механизм под названием «Сжатие», который в основном состоит из фрагментации и повторного связывания объектов в обычной куче. Дело в том, что «сжатие» больших объектов (их копирование и повторное связывание) является дорогостоящей процедурой, GC предоставляет для них другую кучу, которая никогда не сжимается.

Обратите внимание, что выделение памяти происходит непрерывно. Это означает, что если вы выделите Объект № 1, а затем Объект № 2, Объект № 2 будет всегда размещаться после Объекта № 1.

Вероятно, именно из-за этого вы получаете OutOfMemoryExceptions.

Я бы посоветовал взглянуть на шаблоны проектирования, такие как Flyweight, Lazy Initialization и Object Pool.

Вы также можете принудительно собрать сборщик мусора, если вы подозреваете, что некоторые из этих крупных объектов уже мертвы и не были собраны из-за недостатков в вашем потоке управления, в результате чего они достигают более высоких поколений непосредственно перед тем, как быть готовыми к сбору. .

2 голосов
/ 09 марта 2011

Программа всегда бомбит OOM, потому что она запрашивает слишком большой кусок памяти, никогда, потому что она полностью исчерпала все адресное пространство виртуальной памяти.Можно утверждать, что это проблема фрагментации LOH, так же легко утверждать, что программа использует слишком много виртуальной памяти.

Как только программа выходит за рамки выделения половины адресуемой виртуальной памяти (гигабайт)Настало время подумать о том, чтобы сделать свой код умнее, чтобы он не поглощал слишком много памяти.Или сделать 64-битную операционную систему обязательным условием.Последний всегда дешевле.Он тоже не выходит из вашего кармана.

1 голос
/ 20 апреля 2011
Is there any solution to this problem or is it a limitation of CLR memory management?

Нет решения, кроме пересмотра вашего дизайна. И это не проблема CLR. Обратите внимание, проблема та же для неуправляемых приложений. Это объясняется тем фактом, что приложение использует слишком много памяти одновременно и в сегментах, «невыгодно» размещаемых в памяти. Тем не менее, если нужно указать на какого-то внешнего виновника, я бы предпочел указать на диспетчер памяти ОС, который (конечно) не сжимает его адресное пространство vm.

CLR управляет свободными областями LOH в свободном списке. В большинстве случаев это лучшее, что можно сделать против фрагментации. Но поскольку для действительно больших объектов число объектов в сегменте LOH уменьшается - в конечном итоге мы получаем только один объект в сегменте. И где эти объекты расположены в пространстве VM, полностью зависит от менеджера памяти ОС. Это означает, что фрагментация в основном происходит на уровне ОС, а не на CLR. Это часто наблюдаемый аспект фрагментации кучи, и в этом не виноват .NET. (Но это также правда, фрагментация также может происходить на управляемой стороне, как хорошо продемонстрировано в этой статье .)

Общие решения уже названы: используйте ваши большие объекты повторно. Я до сих пор не сталкивался ни с одной ситуацией, когда это не могло быть сделано при правильном замысле. Тем не менее, это может быть сложно иногда и, следовательно, может быть дорогим, хотя.

0 голосов
/ 22 января 2017

Мы обрабатывали изображения в нескольких потоках. Поскольку изображения были достаточно большими, это также вызывало исключения OutOfMemory из-за фрагментации памяти. Мы попытались решить проблему, используя небезопасную память и предварительно выделив кучу для каждого потока. К сожалению, это не помогло полностью, так как мы полагались на несколько библиотек: мы смогли решить проблему в нашем коде, но не сторонние разработчики.

В конце концов мы заменили потоки на процессы и позволили операционной системе выполнять тяжелую работу. Операционные системы давно создали решение для фрагментации памяти, поэтому неразумно игнорировать это.

0 голосов
/ 25 мая 2013

Я видел в другом ответе, что LOH может уменьшаться в размере:

Большие массивы и фрагментация LOH.Что является принятым соглашением?

"... Теперь, сказав, что LOH может уменьшиться в размере, если область на его конце полностью свободна от живых объектов, поэтому единственная проблема заключается в том, чтовы оставляете объекты там на долгое время (например, на время работы приложения). ... "

Кроме того, вы можете заставить вашу программу работать с расширенной памятью до 3 ГБ в 32-битной системе и до 4ГБ на 64-битной системе.Просто добавьте флаг / LARGEADDRESSAWARE в свой компоновщик или в это событие пост-сборки:

call "$ (DevEnvDir) .. \ tools \ vsvars32.bat" editbin / LARGEADDRESSAWARE "$ (TargetPath)"

В конце концов, если вы планируете запускать программу в течение длительного времени с большим количеством крупных объектов, вам придется оптимизировать использование памяти, и вам, возможно, даже придется повторно использовать выделенные объекты, чтобы избежать сборщика мусора, который похож по своей концепции, на работус системами реального времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...