You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

两段Java代码执行结果差异原因探究:println的影响

两段Java代码执行差异的原因分析

代码示例

1. 含System.out.println(i++)的代码

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;
    }
}

执行结果:代码持续运行,短时间内不会抛出内存溢出错误。

2. 无System.out.println(i++)的代码

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;
    }
}

执行结果:代码很快抛出OutOfMemoryError。

差异原因分析

两段代码的核心区别在于循环执行速率和GC线程的调度机会:

  • 第二段代码是纯内存密集型循环,JIT编译器会对其做极致优化,循环执行速度极快,对象创建的速率远远超过GC线程的处理能力。由于ArrayList持有所有Book对象的强引用(GC无法回收这些对象),堆内存会被瞬间填满,直接触发内存溢出错误。

  • 第一段代码中的System.out.println起到了关键的“减速”和“调度触发”作用:

    1. 同步IO拖慢循环速度:println是同步控制台输出操作,每次调用都要等待输出完成才能继续循环,这使得Book对象的创建速率大幅降低,堆内存增长变得非常缓慢,需要很长时间才会被填满,看起来像是“持续运行”。
    2. 触发GC线程调度:IO操作会让当前线程暂时阻塞并让出CPU时间片,GC线程因此获得更多运行机会,能及时清理内存中的临时对象(比如i++转换出的字符串),进一步缓解内存压力。

需要注意的是:第一段代码并非永远不会溢出,只是因为循环速度太慢,内存增长的速度远低于JVM堆内存的容量上限,短时间内不会触发错误。


内容的提问来源于stack exchange,提问作者runoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 16:57:52