2013-02-18 22 views
0

我使用Javolution Struct來表示Java中的C結構。使用Javolution Struct的Java OutOfMemoryError

但是,每次創建新項目時,它都會分配到進程的本機部分,並增加內存使用量。

即使Java堆大小仍然很小,最終該進程仍可達到4GB的內存。這個過程然後被操作系統殺死(我被迫使用一個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根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根20 0 2120m 1.0g 5580 S 115.3 2.8 0:06.00 java -cp。 StructTest
886根20 0 2302m 1.2g 5580 S 23.5 3.3 0:06.24 java -cp。 StructTest
886根20 0 2568m 1.4g 5580 S 180.3 4.1 0:08.08 java -cp。 StructTest
886根20 0 2817m 1.7g 5580 S 95.5 4.8 0:09.09 java -cp。 StructTest
886根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根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 紅帽企業Linux服務器版本6.2(聖地亞哥) 適用於Java 1.6.0_03(1.6.0_03-b05)和64位版本1.6.0_30。

感謝, 鋁

回答

0

繼從yoavain後,看來這確實是一個DirectByteBuffer問題。

在閱讀psot「how to garbage collect a direct buffer 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(); 
     } 
    } 
} 

當我跑了這一點,內存似乎保持穩定。

0

您好我只是跑你的我的機器上的代碼沒有任何問題。

OS: windows 7 
Java: Jrockit 32 bit 

Javolution版本:從SVN

0

最新的,我不認爲這是一個Javolution結構問題。 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(); 
    } 
    } 
}