一个小伙伴的问题

本文探讨了一段代码中加入System.gc()后看似避免了OOM现象的误区,实则因连续Full GC导致OOM延迟。深入解析了讲师可能的初衷及System.gc()的真实作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下午休息的时候,小伙伴突然扔给我一段代码

public class GCTest {
	public static void main(String[] args) {
		List<GCTest> aa = new ArrayList<>();
		for (; ; ) {
			aa.add(new GCTest());
			System.gc();
		}
	}
}

然后问到:为什么不加System.gc()这一行就会OOM,加上System.gc()就不再OOM了。

我问他:哪来的代码?

他说:是看公开课,一个资深讲师讲的,只给了结论说是会GC,所以不OOM,具体原因也没说清楚,所以来问问我怎么回事。

说实话,我当时就蒙了,为什么加上System.gc()就不OOM了呢?多年的“客服”(中间件开发小伙伴的自嘲)经验告诉我,不要相信任何人,先本地验证,再说结论。

先限制下堆大小,快速复现问题。-Xms10m -Xmx10m

果不其然啊,没有System.gc()的时候,很快就OOM了。加上System.gc()的时候,跑很久也没OOM。

但是完全不对啊,和我的认知有冲突啊,完全超出我的知识范围了。不行,再加快OOM速度,再验证。

public class GCTest {
    byte[] bytes = new byte[4096];
    
	public static void main(String[] args) {
		List<GCTest> aa = new ArrayList<>();
		for (; ; ) {
			aa.add(new GCTest());
			System.gc();
		}
	}
}

这回就对了,无论有没有System.gc(),都会很快OOM。

然后截图,发给小伙伴,告诉他:不信谣、不传谣。什么资深讲师,找他退钱。

我们从“资深讲师”的角度,来想一下,为什么他会得出加上System.gc()了,就不会OOM了,这种错误的结论呢?

第一个原因,我想讲师应该是要讲不可达对象的回收:

public class GCTest {

	byte[] bytes = new byte[4096];

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

	private static void test() {
		List<GCTest> aa = new ArrayList<>();
		for (int i = 0; i < 1000; i++) {
			aa.add(new GCTest());
		}
	}
}

当方法退出时,循环创建的1000个GCTest对象就变为了不可达对象,当进行GC时,可以被回收。

第二个原因,我想讲师可能是要讲System.gc()的作用,但是用错了例子。

System.gc()主要是做了哪些内容?这个搜一下,都是以下五条:

  • system.gc其实是做一次full gc
  • system.gc会暂停整个进程
  • system.gc一般情况下我们要禁掉,使用-XX:+DisableExplicitGC
  • system.gc在cms gc下我们通过-XX:+ExplicitGCInvokesConcurrent来做一次稍微高效点的GC(效果比Full GC要好些)
  • system.gc最常见的场景是RMI/NIO下的堆外内存分配等

这也正好说明了,第一次试验加了System.gc()之后,不是没有OOM,而是因为连续的full gc,长时间的stop the world,导致OOM时间延后了而已,如果坚持跑下,依旧会发生OOM的。

并且即使调用了System.gc()也不一定会进行一次full gc,这和实际运行的虚拟机是有关系的,我们常用的hotspot虚拟机实际会根据设置的JVM参数来决定执行什么类型的GC。这部分内容需要看源码,再继续学习了。

综上,主要是想说明一个问题,有时候我们缺的就是对所谓权威的挑战,在技术上只是闻道有先后、术业有专攻而已。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值