Как определить, является ли отношение Strings к char [] в дампе кучи показательным для проблемы? - PullRequest
0 голосов
/ 28 августа 2018

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

 num     #instances    #mb          class name
----------------------------------------------
 1:      11759890      465.61       [C
 2:       3659043      292.89       [Ljava.util.HashMap$Node;
 3:      11762204      282.29       java.lang.String

Поскольку строки представлены символьными массивами, ожидается, что между ними будет корреляция, и в этом случае количество экземпляров каждого из них будет довольно схожим, с разницей в ~ 3000 экземпляров.
Что сбивает с толку, так это несоответствие в использовании двух, учитывая, что char [] составляют на 50% больше байтов, чем Strings.
Поскольку рассматриваемая программа напрямую не содержит экземпляров массивов символов (хотя может быть и зависимость, которую я упустил из виду), создается впечатление, что массивы символов являются единственным источником, но из-за использования памяти я не уверен из, если это ожидается.

Каковы ожидаемые соотношения между массивами символов и строками в отношении экземпляров и использования памяти? В какой момент данные указывают на утечку с одним из двух?

1 Ответ

0 голосов
/ 30 августа 2018

До Java 7 экземпляр обновления String состоял из ссылки на массив char[] и два поля int, offset и length. Вместе с определенными издержками объекта JVM, по крайней мере, двумя словами для HotSpot, он может объяснить в вашей статистике среднее значение 24 байта на String.

В отличие от этого, массив char[] содержит служебные данные, специфичные для JVM, длину, сохраненную как int, и содержимое переменного размера . Так что наблюдение за значительно большим использованием памяти, например, в среднем 40 байтов на массив char[], показанный в вашей статистике, не является чем-то необычным. Не зная больше о вашей конкретной конфигурации JVM, это немного догадка, но если мы предположим 16 байтов для заголовка массива, включая длину и, возможно, заполнение, оставшиеся 24 байта предполагают средний размер массива 12 char с, что не неразумный.

Начиная с Java 7, обновление 6, поля offset и length поля String пропали, что должно уменьшить размер до 16 байт на экземпляр для большинства конфигураций, что может сэкономить ~ 100 МБ для строки экземпляров. И значительно измените соотношение, чтобы char[] экземпляров доминировали в куче еще больше.

По этой причине, начиная с Java 9, экземпляры String состоят только из ссылки на массив byte[]. Если строка состоит только из символов iso-latin-1, что применимо ко многим строкам в типичных приложениях, она будет использовать только один байт на символ, вдвое уменьшая объем памяти для этих строк (для их массива, если быть точным) , Поскольку за пределами этой кодировки будут также строки с символами, конечно, сохранение не будет таким. Но, возможно, еще ~ 100 МБ для вашего приложения.

Но, тем не менее, принимая во внимание среднюю длину строки, указанную выше, память, используемая этими массивами, будет значительно больше, чем память, используемая экземплярами строк, даже при самых последних реализациях. Это нормально.

...