1

在 JConsole 下观察到的以下代码显示了堆大小的不断增加。堆达到最大 25mb,然后 GC 运行并将堆大小减小到近 3MB。这是预期的行为吗?我很惊讶!

public class Dummy {
    public static void main(String[] args) {
        System.out.println("start");
        while(true){
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

我正在使用雪豹。

4

5 回答 5

8

与 jconsole 的通信会导致分配对象。我相信您在这里看到的是您的测量方法的产物。编译代码时,HotSpot 也可能有少量分配。如果您担心,请使用分析器查看正在分配的内容(再次注意分析器界面的分配)。

正常的 GC 行为是为了避免不必要的运行。您将在整个网络上看到内存使用情况的锯齿图。在缓存和交换友好性和避免工作之间存在一些折衷。此外,服务器 HotSpot 在耗尽内存方面比客户端 HotSpot 更积极。

于 2010-01-18T21:34:46.777 回答
4

是的,这应该是预期的行为。虽然您没有做任何特定于分配对象的事情,但 sleep 的实现可能是,即使没有,JVM 中也有其他线程在运行,这很可能是。

于 2010-01-18T21:29:37.933 回答
3

是的,这很正常。您没有显式创建任何对象,但您调用的方法可能会创建一些临时对象作为其实现的一部分。这些临时对象堆积起来,直到 GC 运行清理它们。

于 2010-01-18T21:22:31.797 回答
2

类文件长这样,代码从8循环到14,java.lang.Thread.sleep()是原生的。因此没有理由创建 MB 的对象

 public static void main(java.lang.String[] args);
     0  getstatic java.lang.System.out : java.io.PrintStream [16]
     3  ldc <String "start"> [22]
     5  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]
     8  ldc2_w <Long 5000> [30]
    11  invokestatic java.lang.Thread.sleep(long) : void [32]
    14  goto 8
    17  astore_1 [e]
    18  aload_1 [e]
    19  invokevirtual java.lang.InterruptedException.printStackTrace() : void [38]
    22  goto 8

恐怕你看到的来自 JProfiler 本身(我不知道你是如何将它附加到你的虚拟测试应用程序的)或在这个 vm 中运行的其他东西。如果 JProfiler 未显示此信息,则要找出已创建的对象,您应该进行堆转储。

'

于 2010-01-18T21:35:35.937 回答
1

关于原因,显然有两种理论,根据经验推理无法区分它们。我可以建议一个简单的实验。

  1. 将程序更改为休眠 1 毫秒而不是 5000。(实际数字无关紧要……这是为了使假设的内存分配尽可能快地发生。您也可以尝试 0 毫秒,但休眠的行为可能好吧是不同的......)

  2. 使用当前方法运行程序;例如使用 jconsole。

  3. 在没有 jconsole 等的情况下运行程序,但使用“-verbose:gc”选项,以便您可以看到 GC 何时运行。

我怀疑在最后一种情况下等待 GC 运行时您会失去耐心……甚至sleep尽可能快地调用。

于 2010-01-19T00:16:16.377 回答