为什么结果不同? ‘println’有什么作用

问题描述 投票:0回答:1
public class Test {
    public static void main(String[] args) {

        List<Book> books = new ArrayList<>();
        int i=0;
        for (;;) {
            books.add(new Book("book"));
            System.out.println(i++);
        }
    }
}

class Book {
    private String name;

    public Book(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) {

        List<Book> books = new ArrayList<>();
        int i=0;
        for (;;) {
            books.add(new Book("book"));
        }
    }
}

class Book {
    private String name;

    public Book(String name) {
        this.name = name;
    }
}

为什么结果不同?

  1. 一直运行。
  2. OutOfMemoryError

enter image description here enter image description here

java out-of-memory println
1个回答
0
投票

区别在于速度。

它们最终都会耗尽内存:你正在制作一个占用一些空间的东西(即一本书),并将其添加到一个数组列表(它本身也占用一些空间),从而确保你制作的这个东西不能被垃圾收集。你就这样一直循环下去。

一个快速而另一个慢得多的原因是书籍实例不会占用那么多空间,并且

System.out.println
通过一段疯狂的旅程发送数据,最终将字符发送到IDE 中的控制台视图。 println waits 等待着疯狂的旅程 - 它和整个过程一样慢,而且这个过程并不是特别有效。换句话说,
System.out.println
或多或少相当于
Thread.sleep(10L)
(没有让CPU休息的好处)。它比不需要等待字符出现在 IDE 控制台视图中的代码慢得多。 因此,没有 sysout 语句的代码片段运行速度要快得多,因此,其“每分钟使用的内存”率要大一个数量级。因此,那个片段很快就会因 OutOfMemoryError 崩溃,另一个片段也会这样做,但需要更长的时间。

替代解释:

我真的怀疑这就是正在发生的事情,但是,从理论上讲,也许是可能的:

JVM 进行热点编译。 JVM 进行高级优化(例如,解释它做什么、如何做以及何时做,需要一千页来解释),但仅限于运行大量的代码(想法是:99% 的时间都花在1% 的代码,因此,唯一需要这种处理的代码是那 1%;分析 100% 的代码不是一个好主意,因为这种分析非常昂贵)。没有 sysout 的代码片段连续运行,因此 CPU 非常繁忙,因此,就热点而言,JVM 的行为是不同的。 sysout 端为 JVM 提供了更多的空闲时间来用于早期分析。

这样的分析

可能

确定列表从未被使用,因此,书籍实例未被使用,因此,可以消除该代码。 规则表明这是允许的(不保证“OutOfMemoryError”),但是,我怀疑这种情况会发生。解决这个问题的一种简单方法是使 for 循环条件不是无限的(例如,“只要

System.currentTimeMillis()

为正就循环”,或者循环 100 万亿次,从技术上讲这不是无限的 - 第二个是更好,System.currentTimeMillis()很贵),然后做一些需要书籍仍然存在的事情,从而确保任何热点分析都无法确定“呃,没有人使用列表或书籍,所以我可以完全消除这些行”。

    

© www.soinside.com 2019 - 2024. All rights reserved.