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();
    }
  }
}
Другие вопросы по тегам