Java OutOfMemoryError с использованием Javolution Struct
Я использую Javolution Struct для представления структуры C в Java.
Однако каждый раз, когда я создаю новый элемент, он выделяется в нативной части процесса и увеличивает использование памяти.
В конечном итоге процесс достигает 4 ГБ памяти, хотя размер кучи Java остается небольшим. Затем процесс останавливается операционной системой (я вынужден использовать 32-разрядную версию Java).
Вот небольшой класс, демонстрирующий проблему:
import javolution.io.Struct;
public class StructTest
{
public static class SimpleStruct extends Struct
{
private final Unsigned32 value = new Unsigned32();
}
public static void main(String[] args)
{
try
{
for (int i = 0; i < 10000000 ; i++)
{
SimpleStruct st = new SimpleStruct();
st.value.set(0xFFFF);
if (i % 10000 == 0)
{
long free = Runtime.getRuntime().freeMemory();
long total = Runtime.getRuntime().totalMemory();
System.out.printf("%08d: Total Memory=%,12d ; Used Memory=%,12d\n", i, total, total - free);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Вот "вершина" для этого процесса. Как видите, память увеличивается очень быстро:
886 root 20 0 1617m 447m 5536 S 26,8 1,2 0:00,83 java -cp. StructTest
886 root 20 0 1917m 761m 5536 S 28,2 2,1 0:01,12 java -cp. StructTest
886 root 20 0 2116m 990m 5540 S 359,9 2,7 0:04,80 java -cp. StructTest
886 root 20 0 2120m 1,0g 5580 S 115,3 2,8 0:06,00 java -cp. StructTest
886 корень 20 0 2302 м 1,2 г 5580 S 23,5 3,3 0:06,24 java -cp. StructTest
886 root 20 0 2568m 1,4g 5580 S 180,3 4,1 0:08,08 java -cp. StructTest
886 root 20 0 2817m 1.7g 5580 S 95.5 4.8 0:09.09 java -cp. StructTest
886 root 20 0 3114m 2,0g 5580 S 26,4 5,6 0:09,36 java -cp. StructTest
886 корень 20 0 3406m 2,3 г 5580 S 30,2 6,4 0:09,67 java -cp. StructTest
886 root 20 0 3699m 2,6g 5580 S 25,5 7,3 0:09,93 java -cp. StructTest
886 root 20 0 3994m 2,9g 5580 S 27,4 8,1 0: 10,21 java -cp. StructTest
Я мог бы попытаться использовать структуру, а не воссоздать ее, но мне нужно много элементов в нескольких потоках.
Есть ли простой способ указать процессу освободить память структуры, которая мне больше не нужна?
Редактировать: Проверено на RedHat Linux (в основном 6.2, но также происходит на 5.6). 2.6.32-220.el6.x86_64 Red Hat Enterprise Linux Server, выпуск 6.2 (Сантьяго). Происходит с Java 1.6.0_03 (1.6.0_03-b05) и 64-разрядной версией 1.6.0_30.
Спасибо ал
3 ответа
После сообщения от yoavain кажется, что это действительно проблема DirectByteBuffer.
После прочтения psot " Как собрать мусор в прямом буфере Java", может показаться, что обычный GC не может с этим справиться ("Содержимое прямых буферов может находиться за пределами обычной кучи, собираемой мусором, и поэтому их влияние на объем памяти приложения может быть неочевидным ").
Одним из решений является время от времени активный вызов System.gc(). Это, кажется, очищает память, но ненадежно и громоздко.
Лучшее решение - использовать очиститель буфера и очистить его, когда мы закончим, по сути, "освободив" его как c-код.
Поэтому пересмотренный класс испытаний будет:
import javolution.io.Struct;
import sun.nio.ch.DirectBuffer;
import java.nio.ByteBuffer;
public class StructTest
{
public static class SimpleStruct extends Struct
{
private final Unsigned32 value = new Unsigned32();
}
public static void main(String[] args)
{
try
{
for (int i = 0; i < 10000000 ; i++)
{
SimpleStruct st = new SimpleStruct();
st.value.set(0xFFFF);
if (i % 10000 == 0)
{
long free = Runtime.getRuntime().freeMemory();
long total = Runtime.getRuntime().totalMemory();
System.out.printf("%08d: Total Memory=%,12d ; Used Memory=%,12d\n", i, total, total - free);
}
ByteBuffer byteBuffer = st.getByteBuffer();
if (byteBuffer instanceof DirectBuffer)
{
((DirectBuffer)byteBuffer).cleaner().clean();
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Когда я запустил это, память, казалось, осталась неизменной.
Привет, я просто запустил твой код на моей машине без проблем.
OS: windows 7
Java: Jrockit 32 bit
Версия Javolution: последняя из svn
Я не думаю, что это проблема Javolution Struct. Javolution Struct - это всего лишь оболочка для java.nio.ByteBuffer. Вы могли бы также использовать этот код:
import java.nio.ByteBuffer;
public class ByteBufferTest
{
public static void main(String[] args)
{
try
{
for (int i = 0; i < 10000000; i++)
{
ByteBuffer bb = ByteBuffer.allocateDirect(4);
bb.put(new byte[]{(byte) 255, (byte) 255});
if (i % 10000 == 0)
{
long free = Runtime.getRuntime().freeMemory();
long total = Runtime.getRuntime().totalMemory();
System.out.printf("%08d: Total Memory=%,12d ; Used Memory=%,12d\n", i, total, total - free);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}