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

直接分配给老一代

陆洲
2023-03-14

我有这个程序:

    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正在做的某种优化吗?在旧代中直接创建对象的地方?正如您在下图中看到的,年轻的gc只发生了两次,而老的gc发生了41次。仅旧代GC

接下来,我尝试了相同的代码,只是没有将integer对象添加到链表中,而是创建了一个新的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();
    }
}

没有年轻或年老的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());
    }
}

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

共有1个答案

茹轩昂
2023-03-14

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

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

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

原则上,创建未使用的string实例仍然可以消除,但与不可移除的代码交织似乎违反了优化器的限制。另外,由于随机数生成代码的复杂性,临时字符串的创建在这里被认为与性能无关。

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

 类似资料:
  • 最近我一直在阅读Java不同世代的对象分配。大多数时候,新对象在伊甸园(年轻一代的一部分)中分配,然后如果满足以下任何标准,它们就会晋升为老一代。 (1) 当从伊甸园(或)另一个幸存者空间(从)复制对象时,对象的年龄已达到寿命阈值 (2)幸存者空间(到)已满 但是也有一种特殊情况,即对象直接在旧一代中分配,而不是从年轻一代中提升。当我们试图创建的对象很大(可能是几个MB的数量级)时,就会发生这种情

  • 问题内容: 是否将“静态最终”直接分配给年轻一代或老一代或烫发一代?(我猜想在我认为的时间内,它很可能会降落到旧的gen中。)如果在perm gen中分配了它,那么当在Perm Gen中进行类卸载时,是否会收集垃圾? 问题答案: 是否将“静态最终”直接分配给年轻一代或老一代或烫发一代? 变量引用的对象将根据与其他任何对象相同的规则进行分配。它最有可能在年轻一代或老一代中分配(如果它很大,并且适用某

  • 问题内容: 我希望能够直接调用分配给对象属性的闭包,而无需将闭包重新分配给变量然后再调用它。这可能吗? 下面的代码不起作用,并导致。 问题答案: 从PHP7开始,您可以 或使用Closure ::call(),尽管不适用于。 在PHP7之前,您必须实现magic 方法来拦截调用并调用回调(当然不可能,因为您无法添加该方法) 请注意,您不能做 在体内,因为这会触发无限循环。

  • 我正在为max分配8GB内存给Java编写的应用程序。它会内存溢出。我相信年轻一代总是比默认情况下的老一代小(堆的1/4)。而Eden/幸存者1,2在年轻一代内部。我相信在Eden空间中创建了新对象。 即使老一代还没有满,但年轻一代已经完全满了,java应用程序还是会耗尽内存吗? 如果短寿命的对象比长寿命的对象多,那么可以为年轻一代分配更多内存,或者至少将堆的50%分配给年轻一代吗?或者,由于jv

  • 问题内容: 我是Django的新手,但未找到有关此问题的任何参考。当我在Django模型()中使用多对多字段时,出现此错误。我猜问题是在form()的view()中分配m2m字段。 如何在视图中分配m2m字段?(,) models.py views.py 表格 问题答案: 你需要获取User对象,然后将其添加到字段中。创建实例时,不能向其添加对象。看一下doc。 编辑 这样做的另一种方法是使用。

  • 因此,我昨天开始了一个问题:基于同一行中的值的多个pandas赋值,我想知道如何对一行数据进行排序,并将排序分配给同一行中的不同列。我已经按照Ed Chum的建议解决了这个问题:如何一次将一个函数应用于pandas数据帧中的多个列。 它确实起作用了,但我注意到我在这一过程中创建了错误的列。一旦我修复了这个bug,它就不再工作了。。。。 因此,我尝试在一个玩具示例上重现这个问题,但在玩具示例上也不起