推广 热搜: csgo  vue  angelababy  2023  gps  新车  htc  落地  app  p2p 

内存泄露排查之线程泄露

   2023-08-11 网络整理佚名800
核心提示:静态集合类引起内存泄露监听器:但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。本例(线程泄露)查看线程状况,可线程,发现线程较多,也能定位到,但是为了方便,遂dump一份数据详细观察堆栈线程信息如果每次都new线程而不结束,gc中线程是root节点,如果线程没有结束,不会被回收,所以如果创建大量运行的线程,会导致内存占用量上升,但是线上到底能创建多少线程呢?

根据

内存泄漏(Leak)

java中的内存是由jvm管理的,而垃圾收集是由gc负责的,所以一般情况下不会出现内存泄漏的情况,所以很容易被大家忽略。 内存泄漏是指无用的对象(不再使用的对象)继续占用内存或者无用的对象的内存不能及时释放,造成内存空间的浪费称为内存泄漏。 内存泄漏有时并不严重且难以检测,从而导致开发人员不知道存在内存泄漏,需要独立观察。 更严重的时候,没有内存可以分配,直接oomed。 主要和溢出是有区别的。

内存泄漏

烫发/披露

堆泄漏

更常见的内存泄漏

静态集合类导致监听器内存泄漏:但在释放对象时往往不记得删除这些监听器,从而增加了内存泄漏的机会。 各种连接、数据库、网络、IO、外部模块等内部类的引用:内部类的引用比较容易忘记,而且一旦不释放,后续的一系列类对象也可能不会被释放。 -静态内部类会隐式强引用其外围对象,因此当内部类不释放时,外围对象也不会被释放,从而导致内存泄漏。 单例模式:单例模式使用不当会导致内存泄漏一个常见问题,单例对象在初始化后(以静态变量的形式)会存在于JVM的整个生命周期中,如果单例对象持有一个引用外部对象,那么外部对象将不会被jvm正常回收,其他第三方类会导致内存泄漏

这个例子(线程泄漏)

本案现象

内存使用率达到80%+左右,并且持续上升,最高达到94%

更常见的是,当内存比较高的时候,伴随着

线程数量比较多,最高达到2w+(这个比较重要,可惜后面会关注这个)

日志中伴随大量异常,主要是三类错误

调用翻译接口识别语言服务错误

对接算法提供的二方包请求错误

一开始就走错了弯路

一开始我发现机器内存占用比较大,超过80%+。 这时候我在思考内存相关的逻辑,并没有观察此时的线程数。 根据现象1、2、4,这个过程中我并没有发现现象3,排查无果。 最后,经过重新定位问题,我们发现了现象3。由于现象4的错误日志较多,内存占用较高,所以我们想到了如下思路(因为本例中很多服务都是通过mq消费来启动的)

解决弯路中的疑惑

回到正常的处理逻辑

登录相关机器

top,观察内存使用率(这里的图是重启一段时间后),但是cpu使用率比较高,很快就会下降。 这里有一个延迟,top -Hp pid,确认线程使用率很高,读取一下对应的线程在做什么?

确认螺纹是否有规定尺寸,如果没有找到规定,则使用默认值

查看堆、gc状态

查看线程的状态,但是可以发现线程很多,而且可以定位,但是为了方便,我转储了一条数据来详细观察堆栈

cat /proc/{pid}/ (有这么多线程)

由于线程数量较多,仍然可以创建。 要查看普通Linux用户允许的进程数,使用命令:cat /etc//.d/90-nproc.conf,对比该值,远远超过了当前的数量。

线程信息

线程状态

找到问题线程

==》==》如图,无法直接定位代码块,所以maven定位引用该jar的服务==>具体的二方包。 如果不是每次都终止新线程,则gc中的线程就是根节点。 如果线程没有终止,则不会被回收。 因此,如果创建大量正在运行的线程,内存占用就会增加,但是在线可以创建多少个线程呢? 呢绒?

问题代码块

方法启动(每次初始化一个新的客户端,使用底层封装,使用NIO模型,初始化包括一个boss,10个工作线程)

方法结束(最后调用所有方法)

根据现象和对应的线程堆栈信息,可以判断线程此处溢出。 客户端关闭线程池的方法无效。 导致初始线程处于NIO模式,并没有被终止,所以线程的积压一直在增加,可以修改为单实例。 模式,限制系统使用线程池。

 
反对 0举报 0 收藏 0 打赏 0评论 0
 
更多>同类资讯
推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报
Powered By DESTOON