0

我正在使用 Javolution Struct 来表示 Java 中的 C 结构。

但是,每次我创建一个新项目时,它都会在进程的本机部分分配,并增加内存使用量。

最终,该进程达到 4GB 内存,尽管 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 根 20 0 1617m 447m 5536 S 26.8 1.2 0:00.83 java -cp 。结构测试
886 根 20 0 1917m 761m 5536 S 28.2 2.1 0:01.12 java -cp。结构测试 886 根 20 0 2116m
990m 5540 S 359.9 2.7 0:04.80 java -cp。结构测试 886 根 20 0 2120m
1.0g 5580 S 115.3 2.8 0:06.00 java -cp。结构测试 886 根 20 0 2302m
1.2g 5580 S 23.5 3.3 0:06.24 java -cp。结构测试 886 根 20 0 2568m
1.4g 5580 S 180.3 4.1 0:08.08 java -cp。结构测试 886 根 20 0 2817m
1.7g 5580 S 95.5 4.8 0:09.09 java -cp。结构测试 886 根 20 0 3114m
2.0g 5580 S 26.4 5.6 0:09.36 java -cp。结构测试
886 根 20 0 3406m 2.3g 5580 S 30.2 6.4 0:09.67 java -cp。结构测试 886 根 20 0 3699m
2.6g 5580 S 25.5 7.3 0:09.93 java -cp。
结构测试886 根 20 0 3994m 2.9g 5580 S 27.4 8.1 0:10.21 java -cp。结构测试

我可以尝试重用该结构,而不是重新创建它,但我需要多个线程中的许多项目。

有没有一种简单的方法来指示进程释放我不再需要的结构的内存?

编辑:在 RedHat Linux 上测试(主要是 6.2,但也发生在 5.6 上)。2.6.32-220.el6.x86_64 Red Hat Enterprise Linux Server 版本 6.2 (Santiago) 适用于 Java 1.6.0_03 (1.6.0_03-b05) 和 64 位版本的 1.6.0_30。

谢谢,艾尔

4

3 回答 3

0

嗨,我刚刚在我的机器上运行了你的代码,没有任何问题。

OS: windows 7 
Java: Jrockit 32 bit

Javolution 版本:来自 svn 的最新版本

于 2013-02-21T16:48:33.823 回答
0

我不认为这是一个 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();
    }
  }
}
于 2013-02-21T22:15:51.070 回答
0

根据 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();
        }
    }
}

当我运行这个时,内存似乎保持稳定。

于 2013-02-22T10:33:59.913 回答