方法调用的java内存使用情况

时间:2014-03-01 11:11:07

标签: java memory-management

我正在尝试解决codeeval上的问题,但是遇到了使用太多内存的问题。在我的代码中,由于大量输入是不可避免的,因此有一个循环运行很多次(~10,000 ^ 2)。我注意到如果我运行循环并且在每次迭代时什么也不做,我总共使用大约6MB的内存和其他代码。但是,如果我在循环中添加一个简单的方法调用,它只调用一个返回false的函数,那么我的内存使用量会跳到20MB。

这是为什么?在函数调用完成后,是否不应为每个函数调用分配的内存被释放?

编辑: 完整的代码非常大,与post无关,但这个代码片段就是我所描述的。如果我不包含foo()调用,我的代码作为一个整体运行使用6MB的内存。如果我包含foo()调用,我的代码作为一个整体运行使用20MB的内存。我实际代码中的foo()方法实际上是一样的(返回false),因为我想测试内存使用情况。

这是针对codeeval的编码挑战,所以问题应该可以用他们允许的任何语言解决,所以java应该没问题。

编辑:我已经重构了一些代码,以便我可以提取整个函数来向你们展示。这仍然产生前面描述的相同结果。产生奇怪行为的函数调用是are_friends()

ArrayList<ArrayList<Integer>> graph(String[] word_list) {

    ArrayList<ArrayList<Integer>> adj_list = new ArrayList<ArrayList<Integer>>();

    for (int i = 0; i < word_list.length; i++) {
        adj_list.add(new ArrayList<Integer>());
    }

    for (int i = 0; i < word_list.length; i++) {
        for (int j = i + 1; j < word_list.length; j++) {
            if (are_friends(word_list[i], word_list[j])) {
                adj_list.get(i).add(j);
                adj_list.get(j).add(i);
            }
        }
    }

    return adj_list;
}

boolean are_friends(String a, String b) {
    return false;
}

3 个答案:

答案 0 :(得分:1)

  

如果我包含foo()调用,我的代码作为一个整体运行使用20MB的内存。

您应该注意对Java程序的内存使用情况的明确主张。

  • 你的意思是保留记忆
  • 你的意思是“我在任务管理器/顶级/其他过程监控工具中看到了它?”
  • 你的意思是“我用VisualVM或类似的方式对它进行了分析,这就是堆高峰使用率”?

对于这些方法中的每一种,您可能会得到截然不同的测量结果。

内存使用的一个相关指标是将最大堆大小设置为-Xmx,例如16 MB,并查看您的程序是否能够以其中一种或另一种形式完成无错误。请注意,这将仅限制堆而不是堆栈或JVM使用的任何其他支持内存区域。

在不限制堆的情况下,JVM可以自由地使用它认为合适的数量,保持大量垃圾以避免GC停滞。

答案 1 :(得分:0)

您遇到的问题是,现在它首先会调用一个方法,即foo(),循环运行次数。
并且方法最终会出现在调用堆栈上,需要额外的时间进行处理,为了更深入的解释,您需要谷歌我害怕。

关键是当你将return false置于bar()内时,不会管理调用堆栈,因此使用更少的内存并可能更快。

我相信,在某些时候,如果在Hotspot JVM(默认值)上运行,JVM将内联您的foo()方法调用,从而导致行为就像您直接在return false中有一个bar()。优化时,如果它完成,则取决于JVM参数和您的特定版本/系统。

然而即使已经优化,JVM也会声明内存。即使JVM不再使用内存 ,它也会拒绝将其返回到操作系统,因此您仍然可以观察到更高的内存使用量。

答案 2 :(得分:0)

  

在函数调用完成后,是否不应为每个函数调用分配的内存被释放?

没有。用于调用函数的内存进入堆栈。该线程在线程启动时分配,并且在线程退出之前不会被释放。

  

为什么会这样?

我相信您没有提供有关该问题的所有相关信息。我只是尝试在CodeEval上重现问题,并且在有和没有嵌套循环(500K以内)的情况下获得相同的内存使用。

值得注意的是,相同的代码会在运行到运行的CodeEval上产生不同的内存结果。我没有看到任何与您所看到的一样狂野的偏差,但显然涉及的因素多于代码。