【BUG共赏】记一次线程使用不规范导致的CMS GC

问题背景

早上接到现场反馈,生产环境主机运行一段时间后,性能显著下降,并出现大量的CMS GC
CMS GC:CMS GC发生在老年代,是发生Full GC的前兆,如果开始发生Full GC,就很有可能发生OOM了

日志分析

根据对现场抓取的dump文件用MAT进行分析,发现存在7490个线程对象(java.lang.Thread 类的对象)实例未被释放,占用了大量的内存(推内存,总4.2G,线程对象3.8G,占比91.35%)
在这里插入图片描述
MAT使用详解

知识点:
Leak Suspects:
		通过MAT自动分析当前内存泄露的主要原因;
Shallow Size:
		是对象本身占据的内存的大小,不包含其引用的对象。
		对于常规对象(非数组)的Shallow Size由其成员变量的数量和类型来定,
		而数组的ShallowSize由数组类型和数组长度来决定,它为数组元素大小的总和;
Retained Size:
		=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。
		(间接引用的含义:A->B->C,C就是间接引用) ,并且排除被GC Roots直接或者间接引用的对象;

大大的问号?

令人疑惑:为什么会有这么多线程对象,同时得不到及时释放???
要知道,实际上线程对象本身占用内存是非常小的,如下图:
对应的Shallow Size才120,
而直接引用Retatined heap有15,009,569,
更严重的是间接应用的对象中有60,330, 872大小的,
下图可以看到间接应用对象有业务相关的,这些对象的内存也是没法释放的
在这里插入图片描述

业务日志分析

对线程名称进行分析:例如:pool-7700-thread-1

  • 1.pool开头的线程,说明线程是通过线程池创建
  • 2.pool-xxx(序列) 是线程池的名称,这个说明系统创建了一大推的线程池(搜索结果:7445个 ,这个数量是和MAT工具分析基本匹配)
  • 3.线程名称结尾都是thread-1,也就是说一个线程池就创建了一个线程

那么问题来了:为什么每个线程池就创建了一个线程,同时创建的这个线程不会被关闭呢?
在这里插入图片描述
在这里插入图片描述

合理怀疑手动创建单线程池且未关闭

这时候,应该能猜到一个大概原因了。
合理怀疑是Executors.newFixedThreadPool(1) 这种方式创建的线程池未关闭,导致了创建的线程没有关闭。

	Executors.newFixedThreadPool (nThreads)方式创建线程池,
	输入的参数(nThreads)即是固定线程数,既是核心线程数也是最大线程数,
	不存在空闲线程,核心线程是不会被释放关闭的

按照这个怀疑,搜索了代码,发现有问题的代码如下:
在这里插入图片描述
问题就在这里了!这段代码告诉我们,自己手动去创建线程池是有风险的,容易疏忽忘记了写关闭线程池(忘记写pool.shutdown())

小小的疑问

问题定位出来了,但是关于线程池使用的疑问还在:

  • 1.线程池的代码应该怎么写,才能避免这样的风险和疏忽呢?
  • 2.同时Executors.newFixedThreadPool(1)这种就为了创建一个线程干活(异步去处理事情),每次都去创建一个线程池的方式有必要吗?(创建线程池和线程都会消耗和占用计算机资源)
  • 3.什么时候才有必要手动去创建线程池,应该怎么创建?
    那么线程的正确使用姿势是什么呢?

线程规范

接下来结合具体场景总结下线程池使用的规范:

场景1:异步处理

在业务处理中想要另外起一个线程来处理异步任务,如上面问题场景。

  • 1.可以考虑使用全局的公共线程池,复用资源,避免出现线程池未关闭的情况。
  • 2.线程中的业务代码异常需要捕获打印日志,不要直接抛出业务异常。因为线程异常后线程池会将该线程移除掉,创建新的线程,消耗资源。

场景2:批量数据处理

遇到需要多线程批量处理的需求,就还是手动创建线程池吧。
根据业务实际需求,指定合适的参数(当然这里参数最好不要硬编码,搞成可配置的,方便根据实际情况调整)。
最重要的是要注意任务完成后一定要关闭线程池!!!

 ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
                    KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

如果觉得本文对你有一点点帮助的话 求点赞
如果有其他看法,欢迎在评论区交流!

猜你喜欢

转载自blog.csdn.net/qq_34577234/article/details/125226908
GC