Мое приложение хорошо выполняет двоичную сериализацию и сжатие больших объектов. Несжатый сериализированный набор данных составляет около 14 МБ. Сжатый это около 1,5 МБ. Я обнаружил, что всякий раз, когда я вызываю метод serialize в моем наборе данных, мой счетчик производительности кучи больших объектов увеличивается с менее чем 1 МБ до примерно 90 МБ. Я также знаю, что в относительно загруженной системе, обычно после некоторого времени работы (дней), когда этот процесс сериализации происходит несколько раз, было известно, что приложение выбрасывает исключения памяти, когда этот метод сериализации вызывается, даже если кажется, много памяти. Я предполагаю, что проблема заключается в фрагментации (хотя я не могу сказать, что уверен на 100%, я довольно близок)
Самое простое краткосрочное исправление (думаю, я ищу как краткосрочный, так и долгосрочный ответ), о котором я могу подумать, это вызвать GC.Collect сразу после завершения процесса сериализации. Это, на мой взгляд, соберет мусор объекта из LOH и будет делать это до того, как другие объекты могут быть добавлены к нему. Это позволит другим объектам плотно прилегать к остальным объектам в куче, не вызывая значительной фрагментации.
Кроме этого нелепого распределения в 90 МБ, я не думаю, что у меня есть что-то еще, что использует потерю LOH. Это выделение 90 МБ также является относительно редким (примерно каждые 4 часа). Конечно, у нас все еще будет массив размером 1,5 МБ и, возможно, некоторые другие меньшие сериализованные объекты.
Есть идеи?
Обновление в результате хороших ответов
Вот мой код, который делает работу. Я на самом деле пытался изменить это, чтобы сжать сериализацию WHILE, чтобы сериализация сериализировалась в поток одновременно, и я не получил намного лучший результат. Я также пытался предварительно выделить поток памяти до 100 МБ и пытаться использовать один и тот же поток два раза подряд, LOH в любом случае увеличивается до 180 МБ. Я использую Process Explorer для мониторинга. Это безумие. Я думаю, что я собираюсь попробовать идею UnmanagedMemoryStream дальше.
Я бы посоветовал вам, ребята, попробовать, если вы не захотите. Это не должен быть этот точный код. Просто сериализуйте большой набор данных, и вы получите удивительные результаты (у меня много таблиц, около 15 и много строк и столбцов)
byte[] bytes;
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
serializer.Serialize(memStream, obj);
bytes = CompressionHelper.CompressBytes(memStream.ToArray());
memStream.Dispose();
return bytes;
Обновление после попытки двоичной сериализации с UnmanagedMemoryStream
Даже если я сериализую в UnmanagedMemoryStream, LOH поднимется до того же размера. Кажется, что независимо от того, что я делаю, называется BinaryFormatter для сериализации этого большого объекта будет использовать LOH. Что касается предварительного распределения, это не очень помогает. Скажем, я предварительно выделил, скажем, я предварительно выделил 100 МБ, затем я сериализировал, он будет использовать 170 МБ. Вот код для этого. Даже проще, чем приведенный выше код
BinaryFormatter serializer = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream(1024100);
GC.Collect();
serializer.Serialize(memoryStream, assetDS);
*1024* GC.Collect () в середине находится только для обновления счетчика производительности LOH. Вы увидите, что он выделит правильные 100 МБ. Но затем, когда вы вызываете сериализацию, вы заметите, что она, кажется, добавляет это поверх 100, которые вы уже выделили.