gpt4 book ai didi

java - 直接分配给老年代

转载 作者:行者123 更新时间:2023-11-30 08:08:20 25 4
gpt4 key购买 nike

我有这个程序:

    public static void main(String[] args) {
int sum = 0;
LinkedList<Integer> ll = new LinkedList<>();
for(int i=0;i<Long.MAX_VALUE;i++) {
sum += i;
if (sum % 3 == 0){
ll.add(i);
if (ll.size() % 1000 == 0)
System.out.println("Linked List size: " + ll.size());
}
}
}`

我期望看到的是在年轻代中创建整数对象,其中一些添加到链表中的移动到老年代。所以我希望年轻代 GC 的发生与对象被移动到幸存者空间然后从那里移动到老年代一致。但是我发现一直在发生的是老年代GC,而新生代GC根本没有发生。这是 JVM 正在做的某种优化吗?直接在老年代创建对象的地方?正如您在下图中看到的那样,young gc 只发生了两次,而 old gc 发生了 41 次。 Old Generation GC only

接下来我尝试了相同的代码,只是我没有将整数对象添加到链表中,而是创建了一个新的 Object() 并且令我惊讶的是没有新旧 gc。

public static void main(String[] args) {
int sum = 0;
LinkedList<Integer> ll = new LinkedList<>();
for(int i=0;i<Long.MAX_VALUE;i++) {
sum += i;
Object obj = new Object();
}
}

No Young or Old GC

然后我创建了随机字符串对象:

public static void main(String[] args) {
int sum = 0;
LinkedList<Integer> ll = new LinkedList<>();
for(int i=0;i<Long.MAX_VALUE;i++) {
sum += i;
String s = String.valueOf(Math.random());
}
}

现在我看到熟悉的跷跷板模式,对象被转移到幸存者空间:

5.833: [GC (Allocation Failure) [PSYoungGen: 1048576K->1984K(1223168K)] 1048576K->2000K(4019712K), 0.0035789 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 12.678: [GC (Allocation Failure) [PSYoungGen: 1050560K->2000K(1223168K)] 1050576K->2024K(4019712K), 0.0023286 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 18.736: [GC (Allocation Failure) [PSYoungGen: 1050576K->1968K(1223168K)] 1050600K->2000K(4019712K), 0.0016530 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 24.346: [GC (Allocation Failure) [PSYoungGen: 1050544K->2000K(1223168K)] 1050576K->2040K(4019712K), 0.0016131 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 31.257: [GC (Allocation Failure) [PSYoungGen: 1050576K->1952K(1223168K)] 1050616K->2000K(4019712K), 0.0018461 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 38.519: [GC (Allocation Failure) [PSYoungGen: 1050528K->1984K(1395712K)] 1050576K->2040K(4192256K), 0.0022490 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 47.998: [GC (Allocation Failure) [PSYoungGen: 1395648K->256K(1394176K)] 1395704K->2153K(4190720K), 0.0024607 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]

所以我的问题是 GC 足够聪明,可以看到创建的对象没有在任何地方使用并丢弃它们?为什么不使用字符串?

最佳答案

在您的第一个示例中,您不断地向 LinkedList 添加对象,这是应用程序代码中最旧的对象。一旦这个对象被提升到老年代,将对象添加到该列表意味着修改老年代的成员。这意味着下一次垃圾回收必须检查新创建的对象是否可以被旧对象访问——这实际上是合理的,因为每三个对象都是一个对象。

在您的第二个示例中,您只是创建了一个没有任何副作用的 Object。热点优化器可以消除这样的分配。之后,就再也没有垃圾了。实际上,整个循环可以被消除,因为加法可以被单个乘法代替。但这是否发生与垃圾收集器 Activity (或没有)无关。

第三个示例调用了 Math.random(),它具有全局可见的、不可移除的效果。无论您是否使用返回的数字,它都会提升 Math.random() 内部使用的共享全局随机数生成器的状态。我想,伪随机数生成器的算法太复杂了,无法将循环转换为单个计算步骤。

原则上,未使用的 String 实例的创建仍然可以消除,但似乎与不可删除的代码交错会遇到优化器的限制。也可能是由于随机数生成代码的复杂性,临时字符串的创建在此处被认为与性能无关。

所以您看,第二个和第三个示例与垃圾收集器 没有什么关系,而是与热点优化器有关。此外,关于您的第一个示例,您必须考虑垃圾收集器的工作方式。尽管它的名称如此,但它不是处理垃圾,而是处理 Activity 对象,以找出哪些对象被 Activity 对象引用,因此它们本身是 Activity 的。因此,对象在哪个世代空间中创建并不重要,但哪个对象可以潜在地访问它们。如果自上次收集以来没有旧对象被修改,则可以执行本地收集,因为未修改的旧对象无法到达年轻对象。但是如果一个旧对象被修改了,它的引用必须被遍历以找出它是否引用了新对象。

关于java - 直接分配给老年代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33205491/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com