Retained heap size of a string in java

Это вопрос, который нам было трудно понять. Сложно описать его с помощью текста, но я надеюсь, что суть будет понятна.

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

Однако при профилировании использования памяти с помощью Yourkit или MAT происходит нечто странное. Строка, которая ссылается на сохраненный размер массива символов, не включает сохраненный размер массива символов.

Пример может быть следующим (полупсевдокод):

String date = "2011-11-33"; (24 bytes)
date.value = char{1172}; (2360 bytes)

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

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

Тогда мы имеем следующую ситуацию:

Array's retained size = 300 bytes
array[0] = String 40 bytes;
array[1] = String 40 bytes;
array[1].value = char[] (220 bytes)

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

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

Теперь мы переходим к проблеме.

Я храню в отдельном объекте ссылку на массив, о котором я говорил выше, а также другой массив с теми же строками. В обоих массивах строки ссылаются на один и тот же символьный массив. Это ожидаемо - ведь мы говорим об одной и той же строке. Однако сохраненный размер этого символьного массива учитывается для обоих массивов в этом новом объекте. Другими словами, сохраняемый размер кажется двойным. Если я удалю первый массив, то во втором массиве все еще будет храниться ссылка на символьный массив и наоборот. Это вызывает путаницу, поскольку кажется, что java хранит две отдельные ссылки на один и тот же символьный массив. Как такое может быть? Это проблема с памятью java или это просто способ отображения информации профайлерами?

Эта проблема вызвала у нас много головной боли при попытке отследить огромное использование памяти в нашем приложении.

Еще раз - я надеюсь, что кто-то сможет понять вопрос и объяснить его.

Спасибо за помощь

7
задан slbruce 8 December 2011 в 08:02
поделиться