简述内存泄漏及解决方式

概念

内存泄漏,首先要了解什么是引用,

以下列代码为例,新建对象 B,B 中有个成员变量 a,小 a 上 new 了一个 A 实例,B 就有 A 实例的引用,
这时候,只要 B 存在,A 实例就不会被销毁,

什么时候 A 实例会被销毁呢?给 B 对象 set 一个新的实例,或者设置为 null,旧的 A 实例就可以被销毁。

class A {
}

class B{
    A a = new A();

    public void setA(A a) {
        // set 一个新的实例,旧的那个就可以被被清除
        // 什么时候清除,取决于 java 自身的策略
        this.a = a;
    }
}

而内存泄漏问题,就是因为存在这样的引用关系,对象无法被销毁导致的。

设想一下,如果 A 这个对象有好几个 G,然后不停地 new,内存是不是很快就用完了?

例子一

类似于 while(true) 无限循环,这种情况下,线程不会停止,除非停掉应用程序,如果不断地给线程增加引用,内存占用就会越来越大。

(最常见的就是主线程,写着main函数的那个,只要你程序还在跑,这个函数就仍然在执行)

例子二

程序本身没问题,但是滥用内存,最简单的例子,就是把一整个文件读到内存。

你可能觉得不会有人这么傻,没事读取一整个文件,有些业务确实会不得已为之,像是分析图像文件,需要经常读取整个文件,这时候需要考虑算法方面的优化了。

例子三

一些易错程序的不规范的使用,例如:ThreadLocal、安卓中的 Handler、线程池等等,本身就容易被错误使用,不过人家设计之初,就强调我们需要注意内存泄漏问题。

(其本质上还是线程不能停止,像是线程池,会回收线程重复使用,对于不能停止的线程,使用结束一定要注意置空对象引用)

例子四

静态类(工具类)、静态字段,static 声明的对象会长期霸占内存,需要做好对象的管理工作。

解决方案

一般来说,常规的业务代码,不会导致内存泄漏,保持好良好的编码习惯,及时置空无用的对象引用即可。
(常规代码都能泄漏,可能只是并发量太高,改代码没什么用,要考虑集群部署了)

对于特殊的业务代码,像是图像分析、数据分析,本身也会有一套完整的解决方案,根据场景进行解决即可。

必要的时候,可以使用 “弱引用” 和 “软引用”,内存不足的时候,程序会优先删除这些引用,不过这里就不具体展开说明了。

posted on 2016-10-06 16:05  疯狂的妞妞  阅读(742)  评论(0编辑  收藏  举报

导航