0

JavaでC構造体を表すためにJavolution Structを使用しています。

ただし、新しいアイテムを作成するたびに、プロセスのネイティブ部分に割り当てられ、メモリ使用量が増加します。

最終的に、Java ヒープ サイズは小さいままですが、プロセスは 4GB のメモリに達します。その後、プロセスは OS によって強制終了されます (私は 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 . StructTest
886 root 20 0 1917m 761m 5536 S 28.2 2.1 0:01.12 java -cp . StructTest
886 ルート 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 root 20 0 2302m 1.2g 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.3g 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 (Santiago) Java 1.6.0_03 (1.6.0_03-b05) および 1.6.0_30 の 64 ビット バージョンで発生します。

ありがとう、アル

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 ではこれを処理できないように思われます (「ダイレクト バッファの内容は、通常のガベージ コレクション ヒープの外にある可能性があるため、アプリケーションのメモリ フットプリントは明らかではない場合があります」)。

解決策の 1 つは、時々 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 に答える