【问题标题】:Java process memory check testJava进程内存检查测试
【发布时间】:2014-06-13 09:52:21
【问题描述】:

我试图查看-Xmx-Xms 参数对我的程序的影响,并检查我的进程消耗了多少内存。

我编写了一个简单的程序,但无法推断出结果。请帮忙。

public static void main( String[] args ) {
        char[] array = new char[69926904];
}

我使用参数 -Xms5M -Xmx200M 运行。理想情况下,由于一个字符占用 2 个字节,因此在超过内存限制之前它应该容纳 100M 个字符。即使我们说 pointerlength 使用的空间很少,我也不知道为什么在 69926904 之后会抛出错误em> 长度。

谢谢。

【问题讨论】:

  • @heikkim 感谢您的回复。我浏览了链接。但这里它说Permsize 配置在 Xmx 配置之外。所以这应该不会对同样的权利产生任何影响?
  • 有趣的是,您的结果与每个字符的 3 字节表示一致:(200M * 1024 * 1024) / 69926904 = 2.999...

标签: java memory


【解决方案1】:

仔细阅读JVM Garbage Collection Tuning Guide关于代堆的内容,希望它能回答您的问题。

使用-XX:+PrintGCDetails 选项运行Java,一切都会变得清晰:

Heap
 PSYoungGen      total 3584K, used 294K [0x00000000fbd60000, 0x00000000fc160000, 0x0000000100000000)
  eden space 3072K, 9% used [0x00000000fbd60000,0x00000000fbda9860,0x00000000fc060000)
  from space 512K, 0% used [0x00000000fc0e0000,0x00000000fc0e0000,0x00000000fc160000)
  to   space 512K, 0% used [0x00000000fc060000,0x00000000fc060000,0x00000000fc0e0000)
 PSOldGen        total 136576K, used 136576K [0x00000000f3800000, 0x00000000fbd60000, 0x00000000fbd60000)
  object space 136576K, 100% used [0x00000000f3800000,0x00000000fbd60000,0x00000000fbd60000)
 PSPermGen       total 21248K, used 2595K [0x00000000ee600000, 0x00000000efac0000, 0x00000000f3800000)
  object space 21248K, 12% used [0x00000000ee600000,0x00000000ee888db0,0x00000000efac0000)

您的 200M Java 堆由 2 代组成:1/3 (66.7M) 是 YoungGen,2/3 (133.3M) 是 OldGen。

-XX:NewRatio 选项允许改变比例,但默认值为 2 表示 YoungGen 将保留 1/(2+1) 部分堆。

Java 对象不能跨代,因此对象的最大大小不能大于最大代。在您的情况下,最大的一代是 OldGen:136576K = 139853824,这正是 char[69926904] 的大小(16 字节标头 + 2 * 69926904 字节数据)。

【讨论】:

  • “对象的最大大小不能大于最大的代”。超级整洁:D
【解决方案2】:

此信息来自 Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine 上的 Oracles 页面。

堆和世代

首先了解堆的工作原理很重要。您可能知道对象(如您的数组)存储在堆中。然而,堆并不是一个统一的空间。它实际上分为三代,分别是YoungTenuredPermanent一代。

垃圾收集发生在每一代填满时。对象首先在年轻代中分配,并且由于婴儿死亡率,大多数对象都死在那里。一些幸存的对象被移动到一个tenured generation。当需要收集终身代时,有一个主要收集通常会慢得多,因为它涉及所有活动对象。

“年轻一代由伊甸园和两个幸存者空间组成。 对象最初是在伊甸园中分配的。一个幸存者空间是空的 随时,并作为下一个目的地,复制 收集伊甸园和其他幸存者空间中的任何活动对象。 对象以这种方式在幸存者空间之间复制,直到它们 年龄足以被终身制,或复制到终身制。”

“与终身代密切相关的第三代是 永久一代。永久代是特殊的,因为它 保存虚拟机需要的数据来描述对象 在 Java 语言级别上没有等价物。例如 描述类和方法的对象存储在永久 一代。”

一些参数

除了控制总堆大小的-Xms-Xmx 参数之外,还有控制各个段大小的参数。在您的示例中,您设置了最大总堆大小,但您仍在使用默认生成比率。

"默认情况下,新生代大小由NewRatio控制。对于 例如,设置 -XX:NewRatio=3 表示年轻之间的比例 终身代是1:3。换句话说,组合的大小 伊甸园和幸存者空间将占总堆的四分之一 大小。”

问题

"在理想的次要集合中,活动对象是从一个 年轻代的一部分(伊甸园空间加上第一个幸存者 空间)到年轻代的另一部分(第二个幸存者) 空间)。但是,不能保证所有活动对象都会 适合第二个幸存者空间。为确保未成年人 即使所有对象都处于活动状态,也可以完成收集,足够空闲 内存必须在tenured generation中保留以容纳所有 活的物体。在最坏的情况下,这个保留的内存等于 伊甸园的大小加上非空幸存者空间中的对象。什么时候 终身代中没有足够的可用内存 最坏的情况下,会发生一个主要的收集。

您要做的是存储一个巨大的巨大物体。这个对象必须适合其中的一代,而且根本没有足够大的一代。即使堆的总大小大于对象,这也无济于事,因为对象不能跨越多代。

尝试的事情

在运行代码时尝试添加以下参数:-XX:NewRatio=10。如上所述,这将使tenured generation 成为young generation 的十倍。结果,一个更大的对象将能够容纳在终身代中。

另一种解决方案是简单地避免使用巨大的物体。与其拥有一个庞大的阵列,不如拥有几个较小的阵列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-19
    • 2015-11-17
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    相关资源
    最近更新 更多