Могу ли я использовать меньше памяти при использовании DeflateStream? - PullRequest
1 голос
/ 27 мая 2009

Мое приложение должно распаковывать файлы, которые содержат много сжатых блоков Deflate (а также другие типы сжатия и шифрования). Профилирование памяти показывает, что конструктор потока deflate отвечает за выделение большей части памяти приложения в течение срока его службы (54,19%, затем DeflateStream.read с 12,96% и все остальное менее 2%).

Чтобы поместить это в перспективу, каждый блок файла обычно 4 КБ (распакован), а конструктор DeflateStream выделяет чуть больше 32 КБ (предположительно для скользящего окна). У сборщика мусора есть полевой день, так как все эти потоки выкачивания длятся почти без времени (каждый уходит до того, как приходит следующий)! До свидания эффективность кеша.

Я могу продолжать использовать DeflateStream, но мне интересно, есть ли лучшая альтернатива. Может быть, способ сбросить поток и использовать его снова?

Ответы [ 3 ]

3 голосов
/ 27 мая 2009

Два комментария без какого-либо фактического измерения, подтверждающие это:

  • Я думаю, вы обнаружите, что количество времени, занимаемое выделением (и обнулением) этих временных буферов, ничтожно мало по сравнению со временем, потраченным на фактическую распаковку.
  • Тот факт, что эти буферы являются высокопереходными, означает, что хотя в течение времени жизни приложения оно может составлять 50% памяти, ни один из них не существует одновременно. Обратите внимание, что это также не должно сильно влиять на эффективность кеша ... Я полагаю, что большинство этих буферов не сильно переживут свое использование в кеш-памяти, потому что страницы очень быстро устаревают.

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

2 голосов
/ 27 мая 2009

В DotNetZip есть DeflateStream, фактически заменяющий встроенный DeflateStream в .NET BCL. Ionic.Zlib.DeflateStream имеет настраиваемый размер буфера. Я не знаю, приведет ли это к повышению эффективности памяти в вашем сценарии, но, возможно, стоит попробовать. Вот документ .

Я не тестировал декомпрессию, а скорее сжатие. В моих тестах я обнаружил ограниченную отдачу от расширения размера буфера за пределы 4 КБ для подмножества сжатых данных. С другой стороны, вы все равно получаете точное и правильное сжатие, хотя оно менее эффективно, даже если размер буфера составляет 1024 байта. Я полагаю, вы увидите похожие результаты в декомпрессии.

В любом случае размер окна не может быть установлен напрямую из открытого интерфейса. Но это с открытым исходным кодом, и вы сможете легко изменить размер Wwindow по умолчанию в зависимости от ситуации. Кроме того, если вы считаете, что это ценно, я мог бы запросить размер окна в качестве устанавливаемого параметра в DeflateStream. Я не обнародовал это, потому что никто не просил об этом. Тем не менее

Вы сказали, что у вас тоже было другое сжатие. Если вы используете Zlib или GZip, в пакете DotNetZip также есть ZlibStream и GZipStream.

Если вы хотите создавать Zip-файлы, вам нужна полная библиотека DotNetZip (Ionic.Zip.dll, ~ 400k). Если вы просто делаете {Deflate, Zlib, GZip} Stream, то есть Ionic.Zlib.dll, который составляет около 90 КБ.

DotNetZip бесплатен, но пожертвования приветствуются .

2 голосов
/ 27 мая 2009

Есть ли у вас реальные проблемы с производительностью, или вы просто беспокоитесь об использовании памяти?

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

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

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

...