6

我需要找出我真正接近的时间,OutOfMemoryError以便我可以将结果刷新到文件并调用runtime.gc();. 我的代码是这样的:

Runtime runtime = Runtime.getRuntime();
...
if ((1.0 * runtime.totalMemory() / runtime.maxMemory()) > 0.9) {
... flush results to file ...
  runtime.gc();
}

有一个更好的方法吗?有人可以帮帮我吗?

编辑

我明白我是在用这种方式玩火,所以我推断出一种更可靠、更简单的方法来确定我什么时候受够了。我目前正在使用 Jena 模型,所以我做了一个简单的检查:如果模型有超过 550k 的语句,那么我会刷新,所以我不会冒任何风险。

4

2 回答 2

3

首先:如果你想确定你是否接近OutOfMemoryError,那么你所要做的就是将当前内存与 使用的最大内存进行比较JVM,以及你已经做过的事情。

第二:您想将结果刷新到文件,我想知道为什么要在接近时这样做OutOfMemoryError,您只需使用类似 a 的东西,FileWriter它有一个缓冲区,所以如果缓冲区被填满,它会自动刷新结果。

第三:永远不要GC显式调用,这是一种不好的做法,JVM而是优化你的内存参数:

-Xmx -> this param to set the max memory that the JVM can allocate
-Xms -> the init memory that JVM will allocate on the start up
-XX:MaxPermSize= -> this for the max Permanent Generation memory

-XX:MaxNewSize=  -> this need to be 40% from your Xmx value
-XX:NewSize= -> this need to be 40% from your Xmx value

这些将加速 GC。

-XX:+UseConcMarkSweepGC启用CMS用于旧空间。

于 2014-03-04T11:57:07.607 回答
1

这似乎有效:

public class LowMemoryDetector {

    // Use a soft reference to some memory - will be held onto until GC is nearly out of memory.
    private final SoftReference<byte[]> buffer;
    // The queue that watches for the buffer to be discarded.
    private final ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
    // Have we seen the low condition?
    private boolean seenLow = false;

    public LowMemoryDetector(int bufferSize) {
        // Make my buffer and add register the queue for it to be discarded to.
        buffer = new SoftReference(new byte[bufferSize], queue);
    }

    /**
     * Please be sure to create a new LMD after it returns true.
     * 
     * @return true if a memory low condition has been detected.
     */
    public boolean low () {
        // Preserve that fact that we've seen a low.
        seenLow |= queue.poll() != null;
        return seenLow;
    }
}

private static final int OneMeg = 0x100000;

public void test() {
    LowMemoryDetector lmd = new LowMemoryDetector(2*OneMeg);
    ArrayList<char[]> eatMemory = new ArrayList<>();
    int ate = 0;
    while ( !lmd.low() ) {
        eatMemory.add(new char[OneMeg]);
        ate += 1;
    }
    // Let it go.
    eatMemory = null;
    System.out.println("Ate "+ate);
}

它打印

Ate 1070

为了我。

使用大于您正在使用的最大分配单元的缓冲区大小。它需要足够大,以便在释放缓冲区时满足任何分配请求。

请记住,在 64 位 JVM 上,您可能正在运行许多 tb 内存。在这种情况下,这种方法几乎肯定会遇到很多困难。

于 2014-03-04T11:50:14.137 回答