当前位置: 首页 > 知识库问答 >
问题:

使用G1收集器,是否可以将一个数组对象分配给不同的

安明亮
2023-03-14

//VM args:-verbose:gc-xms20m-xmx20m-xmn10m-xx:+printgcdetails-xx:survivorratio=8-xx:+useg1gc

public static void testAllocation() {
     byte[] allocation1, allocation2, allocation3, allocation4;
    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB];
    allocation4 = new byte[4 * _1MB];
}

public static void main(String[] args) {
    testAllocation();
}

运行该程序我得到以下结果:

[GC暂停(G1巨大分配)(年轻)(初始标记),0.0015208秒]......

堆垃圾-第一堆总计20480K,已使用10816K[0x00000007BEC00000,0x00000007BED000A0,0x00000007C0000000)区域大小1024K,2个年轻(2048K),1个幸存者(1024K)元空间已使用3308K,容量4496K,提交4864K,保留1056768K类空间已使用365K,容量388K,提交512K,保留1048576K

=================================================================================================================================================

数组大小为2MB或4MB,区域大小为1MB,有没有人能告诉我为什么它使用了2个年轻区域和1个幸存者?

共有1个答案

南门野
2023-03-14

首先,您指定了-xx:survivorratio=8,但是-xx:+useAdaptiveSizePolicy是打开的,因此survivorratio被忽略。

然后,我解释了你在这个答案中看到的一些行。

无论如何,我使用java-13和Unified Logging运行了它,特别是使用:

"-Xlog:heap*=debug" "-Xlog:gc*=debug"

看看是怎么回事。

从日志中,我看到只有两个GC循环,作为这段代码的一部分。实际上,它只是一个并发循环,但作为该循环的一部分,young GC也被触发。从逻辑上讲,我将其视为单个GC循环,但GC将报告记录为两个。

因此,您的日志将包含:

[0.127s][debug][gc,ergo] Request concurrent cycle initiation (requested by GC cause). GC cause: G1 Humongous Allocation

此外,您还将拥有:

[0.133s][info ][gc    ] GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation) 7M->6M(20M) 5.753ms
[0.133s][info ][gc,cpu] GC(0) User=0.01s Sys=0.00s Real=0.01s
[0.133s][info ][gc    ] GC(1) Concurrent Cycle

请注意并发周期是如何从年轻周期附带的。

现在,来回答关于区域的问题。

gc(0)以:

[0.127s][debug][gc,heap] GC(0) Heap before GC invocations=0 (full 0)...
[0.127s][debug][gc,heap] GC(0) region size 1024K, 1 young, 0 survivors

因此,从1 Young=1 Eden+0 Survivers开始

后面会有一个日志:

[0.133s][info ][gc,heap] GC(0) Eden regions:     1 -> 0 (9)
[0.133s][info ][gc,heap] GC(0) Survivor regions: 0 -> 1 (2)

正如我在上面给出的链接中所解释的,下一个循环的young GC将被暗示使用:

11 young regions = 9 Eden + 2 Survivor

但是,正如我在那里所说,这只是一个暗示。由于这是一个很大的分配,它实际上将使用较少的区域,正如您退出时堆布局所看到的:

[0.157s][info ][gc,heap,exit]  garbage-first heap   total 20480K....
[0.158s][info ][gc,heap,exit]  region size 1024K, 2 young 1 survivors

GC不知道您只分配大的对象,它不应该使用任何年轻的区域,它的启发式仍然告诉创建一些年轻的区域。这就是为什么你会看到那些2年轻,1幸存者

但是,如果您运行代码的时间足够长:

public static void main(String[] args) {
    while (true) {
        invokeMe();
    }
}

public static int invokeMe() {
    int x = 1024;
    int factor = 2;
    byte[] allocation1 = new byte[factor * x * x];
    allocation1[2] = 3;
    byte[] allocation2 = new byte[factor * x * x];
    byte[] allocation3 = new byte[factor * x * x];
    byte[] allocation4 = new byte[factor * factor * x * x];

    return Arrays.hashCode(allocation1) ^ Arrays.hashCode(allocation2)
        ^ Arrays.hashCode(allocation3) ^ Arrays.hashCode(allocation4);
}
[0.521s][debug][gc,heap] GC(62) Heap before GC invocations=62 
[0.521s][debug][gc,heap] GC(62) region size 1024K, 0 young (0K), 0 survivors (0K)

请注意0年轻,0幸存者

 类似资料:
  • 问题内容: 在Python中,我需要一个类似于以下内容的字典对象: 我已经可以通过结合和这样的功能成功获得此功能: 但是,由于该代码是为新手用户编写的,他们有时可能需要添加键/值,所以我更喜欢简单的准系统(类似于Perl)的语法,例如: 但是,这给了我: 有什么方法可以进一步简化我的第一个示例(使用和),并获得我要查找的dict对象? 或者,或者,如果像我的第二个示例那样,我有一个包含元组的字典,

  • 我尝试用以下方法调用三个引用游标参数: 但是listOfObjects只包含cursor1的内容,无法获得cursor2的内容。

  • 我已经读到,在以下情况下,对象可以进行垃圾收集。 该对象的所有引用都显式设置为null 但是,是否有无论如何要标识的对象是合格的垃圾回收机制是由垃圾收集器收集?

  • 问题内容: 有没有一种方法可以检查垃圾收集器是否可以提取对象? 在我的代码中的某个地方,我有一个对象的引用: 然后,通过Eclipse Debugger,获得对象的存储位置。之后,我将引用设置为null: 有什么方法可以检查以前引用的对象现在是否适合垃圾回收,或者是否有其他引用? 非常感谢, 斯特凡 问题答案: 您无法在运行时使用任意对象执行此操作,实际上,不可能完全确定地执行此操作。但是,有两种

  • 我制作了一个类 在另一个类中 正如您所看到的,我创建了这个数组,并将UImages与txt和txt2一起放置在其中。简单地说,我要向用户显示一个图像,然后输入一个描述图像的输入,然后检查它是否匹配txt和txt2。在运行模拟器时,我得到以下错误: ***由于未捕获异常“nSunKnownKeyException”而终止应用程序,原因:“[ SetValue:ForUndefinedKey:]:对于

  • 我基本上有一个但是我不需要这个数组中的所有位置。我可以创建另一个节点结构来动态地只设置适当的位置,但这将更加困难,因为我的特定程序依赖于矩阵的索引。如何有选择地释放矩阵的某些索引。 例如,对于特定节点,我不需要uint64_t[4][3]或uint64_t[7][3],如何释放该节点?