Собирается ли мусор в оболочках Java DirectByteBuffer? - PullRequest
10 голосов
/ 14 июля 2011

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

Например, если бы я выделил новый dbb DirectByteBuffer, а затем дублировал (поверхностно скопировал) его, используя dbb.duplicate (), у меня было бы два обертки вокруг одного и того же куска памяти.

Являются ли эти обертки объектом сбора мусора? Если бы я сделал

while(true){
    DirectByteBuffer dbb2 = dbb.duplicate();
} 

Буду ли я в конечном итоге сам ООМ?

Ответы [ 4 ]

14 голосов
/ 14 июля 2011

В Sun JDK a java.nio.DirectByteBuffer - созданный ByteBuffer#allocateDirect(int) - имеет поле типа sun.misc.Cleaner, которое расширяется java.lang.ref.PhantomReference.

Когда этот Cleaner (помните, подтип PhantomReference) собирается и собирается переместиться в связанный ReferenceQueue, связанный с коллекцией поток, проходящий через вложенный тип ReferenceHandler, имеет специальный регистр обработкиCleaner экземпляров: он преуменьшает значение и вызывает Cleaner#clean(), что в конечном итоге возвращается к вызову DirectByteBuffer$Deallocator#run(), который, в свою очередь, вызывает Unsafe#freeMemory(long).Вау.

Это довольно круто, и я был удивлен, не увидев никакого использования Object#finalize() в игре.У разработчиков Sun, должно быть, были причины связать это еще ближе с подсистемой управления сбором и ссылками.

Короче говоря, вам не хватит памяти из-за отказа от ссылок на экземпляры DirectByteBuffer,до тех пор, пока сборщик мусора сможет заметить отказ и его поток обработки ссылок будет проходить через вызовы, описанные выше.

3 голосов
/ 14 июля 2011

Прямой объект ByteBuffer аналогичен любому другому объекту: его можно собирать мусором.

Память, используемая прямым буфером, будет освобождена, когда объект ByteBuffer имеет значение GC'd (это явно не указано для ByteBuffer, но подразумевается в документации MappedByteBuffer).

Интересно, когда вы заполнили пространство виртуальной памяти прямыми буферами, но все еще многокомнаты в куче.Оказывается, что (по крайней мере в Sun JVM), когда виртуальное пространство выделяется при выделении прямого буфера, запускается GC кучи Java.Который может собирать прямые ссылки на буферы и освобождать их выделение виртуальной памяти.

Если вы работаете на 64-битной машине, вы должны использовать -XX:MaxDirectMemorySize, что накладывает верхний предел на количество буферов, которые вы используете.может выделять (а также вызывает GC при достижении этого предела).

1 голос
/ 14 июля 2011

Глядя на исходный код на DirectByteBuffer, он просто возвращает новый экземпляр, так что нет, вы сами не получите OOM.

Пока остальная часть вашего кода не удерживает ссылкук исходному dbb, тогда этот объект будет собирать мусор как обычно.Дополнительные dbb2 объекты также будут собирать мусор, когда на них больше не будет ссылок (т. Е. Конец цикла while).

0 голосов
/ 15 июля 2011

когда выделен прямой байтовый буфер, он не подлежит сборке мусора

Откуда вы взяли эту идею?Это не правильно.Вы путаете их с MappedByteBuffers?

...