Java内存泄漏问题排查&&解决方法

187 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

之前,在组里帮忙做的一个小 Demo,“交付”给组长看后,提出了一些页面上的缺陷,需要优化(后期会通过文章来记录 Vue + ElementUI 做页面过程中的技术点)。总之看过之后,组长还告知我,我之前打的 jar 包放在服务器上运行的时间过长的话,占用的内存就会很大,有就将近20G,甚至还存在过 CPU 被占满的情况(后续没有复现),让我排查一下。第一次真正在生产中面对内存泄漏问题,一时间懵了,无从下手。仔细想了想,反正自己也没加很多代码,接口也不多,方法也都是自己刚写的,比较熟悉。查起来应该问题不大,但关键就是该怎么排查。

一、静态全局变量 看了一遍自己写的接口,其中有一个 mapper 中,上来我就定义了一个静态的全局变量

微信图片_20220727193539.png

当时,设置这个静态变量,我想的是后续可能很多方法都会用到这个变量,所以干脆定义成了全局的 static,但最后写来写去,也就一个方法用到了这个变量,我想着没影响,就没改。查资料后反应过来,可能是我定义的这个私有静态变量,其生命周期跟程序是一致的。长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。

二、集合 这种情况,我的代码中也存在,我感觉可能也是导致内存泄露的一个原因。我在代码中写有,在方法返回时,返回的是一个集合,而这个集合中还存在对其他对象的引用。类似:

    public class Stack {
        private int size = 0;
        
        public Object test() {
            if (size == 0) {
                XXXXXXXXX
            }
            return testList[size++];
        }
    }

这种情况,好像也是一个内存泄漏的状况,比较隐蔽。因为 testList 中存在对 size 的引用,如果 size 不等于 0,即使方法结束,但集合 testList 中仍然存在对 size 的引用,所以导致 GC 不能将其回收,最终导致内存泄漏,俗称过期引用。

解决方法:

    public class Stack {
        private int size = 0;
        
        public Object test() {
            if (size == 0) {
                XXXXXXXXX
            }
            Object result = testList[size++];
            testList[size] = null;
            return result;
        }
    }

自己的代码中,我暂时就发现了这两处,而且还不确定到底是不是这两个地方的原因导致了内存泄漏。明天到公司再看看吧,也许上面提到的有错误的地方,还请见谅,因为我也雀食不太懂,还望指正。
我向你敬礼啊,Salute!