内存泄漏及解决方案

内存泄漏


定义

某些对象或者数据没有利用价值了,但是由于某些原因占用着内存,无法被回收,就造成了内存泄漏。

例子:比如说有一个数组对象,占用内存很大,在使用完毕以后,还有强应用引用着该数组对象,那么这块内存就无法回收。


内存泄漏种类

Java使用的内存种类包含三种,这三种类型的内存都可能发生内存泄漏。

  • 堆内存泄漏:
    • 如果在JVM中没有足够的内存空间分配给java对象,将会抛出OOM错误。
    • 原因:一般情况下是程序出现了问题,生成的对象占用过多堆内存,并且没有及时释放,从而造成内存泄漏
  • 本地内存泄漏:
    • 如果JVM无法获取更多的本地内存,它将抛出OOM错误。
    • 为什么无法获取更多的本地内存?内存被占用过多了,不够了
    • 原因:Java调用本地方法,这些本地方法有内存泄漏。

解决方法

压力测试环境,对一Java应用服务进行12小时稳定性压测,压测结束后服务器的CPU使用率还很高,使用top使用观察Java进程使用了720%,机器配置为8C。

image-20200223181949500

使用jstat命令查看java进程,eden区内存占用了接近100%,老年代占用了99.79%,从FGC列看到JVM在不断做Full GC操作。

image-20200223181310275

通过上述分析,可以确定问题的原因是JVM有内存泄漏。

JVM内存泄漏问题的解决相对来说比较简单。

  1. 使用下面的命令dump出JVM内存映像

    jmap -dump:format=b,file=mydump.bin pid
    生成的dump文件会比较大,比JVM配置的堆大小相当

  2. 将dump文件下载到本地,因为分析dump文件比较耗费服务器资源,不要影响到线上服务器

  3. 使用内存泄漏工具分析这个dump文件,比如说MAT。

    找到占用内存最多的对象,结合程序分析这个对象在程序中的使用,一般很容易就定位出内存泄漏的原因。

PS:上述其实是由于CPU打满了,然后发现原因是频繁FullGC。而频繁Full GC的原因是因为发生了内存泄漏。


实战

首先有一个程序,存在内存泄漏:

/**
 * 内存泄漏示例
 * @author huangy on 2020-02-23
 */
public class OOMDemo {

    public static void main(String[] args) throws Exception {

        // 程序运行的时候,生成一个大的数组对象,然后没有释放
        int[] arr = new int[1024 * 1024];

        while (true) {
            Thread.sleep(1000);
        }
    }


}

使用jps查看java进程pId:

image-20200223182957908

使用jmap -dump:format=b,file=mydump.bin 6384导出内存快照文件

image-20200223183051992

使用MAT定位使用内存最多的内存,再定位到代码位置

首先找到Dominator Tree,如下图:

image-20200223185849846

打开Dominator Tree,按照内存占用从大到小排序:

image-20200223185943518

找到占用内存最多的对象

image-20200223190022411


参考

内存泄漏及解决方法

Mac版MAT的安装

MAT分析dump文件

堆外内存泄漏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值