Частая сборка мусора при попытке использовать Object для преобразования в байтовый массив - PullRequest
0 голосов
/ 22 октября 2019

Я использую приведенный ниже код для преобразования объекта в байтовый массив.

ByteArrayOutputStream baoS= new ByteArrayOutputStream();        
objectOutputStream ooS = new ObjectOutputStream(baoS);
ooS.writeObject(object);        
ooS.flush();        
ooS.close();
return baoS.toByteArray();

Мы сталкиваемся с частыми проблемами GC и медлительностью в производственной среде. У нас есть много объектов, поступающих во время выполнения, и вышеупомянутый код будет вызываться для преобразования объекта в байтовый массив. Приведет ли этот код к утечке памяти / увеличению загрузки процессора при частом вызове? Переданный объект является списком. Этот метод оказался узким местом при выполнении выборки с помощью JVisualVM.

1 Ответ

0 голосов
/ 22 октября 2019

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

Переданный объект является списком. Этот метод оказался узким местом при выполнении выборки с помощью JVisualVM.

Если список огромен, тогда у вас в куче две огромных вещей:

  1. список
  2. версия списка байтового массива

2 обманчива. Буфер по умолчанию в ByteArrayOutputStream составляет 32 байта. Сообщения большего размера приведут к созданию другого массива , который в два раза больше, и копированию данных. А если этого недостаточно, создайте другой массив и скопируйте снова. и т. д. и т. д. Это много работы!

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

Следующее простое решение - предварительный размер буфера. Если вы знаете, что 98% сообщений имеют размер менее 16 КБ, то вы можете просто объявить об этом заранее: new ByteArrayOutputStream(16384);. Теперь 98% всех копий массива, увеличившихся с 32 байт до 16834, исчезли. Правда, это неэффективно для сообщений, которые на самом деле крошечные, но, возможно, это чистый выигрыш.

Или вместо фиксированного размера буфера, вы можете догадаться: new ByteArrayOutputStream(guessBufferSize(theList));

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

...