什么是内存泄露

RenatoLapsl 4年前
   <p>在android项目开发中,通常会有针对应用的性能优化,其中对内存优化是必不可少的环节。在此整理下内存优化中的内存泄露</p>    <p>说到内存泄露(Memory Leak),首先要了解下内存管理。Java的内存管理就是对象的分配和释放问题。通过关键字 new 为每个对象申请内存空间 (基本类型除外);对象的释放则由 GC 决定和执行的。GC 监控着每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等。监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就是该对象不再被引用。</p>    <p>如何判断对象不可用?</p>    <ul>     <li> <p><a href="/misc/goto?guid=4959717444828664302" rel="nofollow,noindex">引用计数器法(Reference Counting Collector)</a></p> 引用计数是垃圾收集的 早期策略 。每一个对象都有一个引用计数。一个对象被创建了,并且指向该对象的引用被分配给一个变量,这个对象的引用计数被置为1。当任何其他变量被赋值为对这个对象的引用时,计数加1。当一个对象的引用超过了生存期或者被设置一个新的值时,对象的引用计数减1。任何引用计数为0的对象可以被当作垃圾收集。这种方存在一个问题,如图所示: <p>循环引用(Circular references)</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/f43fc01a9dbe54f1d77c77f1e44a6c1e.png"></p> </li>    </ul>    <p>如图所示,顶部对象皆不可达,但却相互引用,基于引用计数器法,则不会被回收。</p>    <ul>     <li> <p>可达性分析法/根集算法( GC Roots )</p> </li>    </ul>    <p style="text-align:center"><img src="https://simg.open-open.com/show/95bfa2c39c021991a9ec09ccadd5ddf2.jpg"></p>    <p> </p>    <p>如图所示,通过一系列的“GC Roots”的对象作为起始点,从这些节点开始往下搜索,搜索的走过的路径称为引用链,当一个对象到“GC Roots”没有引用链可达时(也就是用图论的话说就是从GC Roots到这个对象不可达),则证明此对象是不可用的,这样的对象被判定为是可回收的。</p>    <ul>     <li> <p>其他GC算法...</p> </li>    </ul>    <p>综合以上,可以回答标题的问题了,什么是内存泄露?</p>    <p>答: 某一个对象不再被程序所使用了(无用的对象),但是它却一直被持有(引用),导致无法正常被gc回收,所占的内存空间无法释放,那么可以说在这个对象发生了内存泄露</p>    <p>如何判断一个对象发生了内存泄露?</p>    <p>结合以上说明,我们可以得出结论,不论说明对象,发生内存泄露的条件是:</p>    <ul>     <li> <p>该对象不可用<br> 在程序运行中,不再使用该对象。用图论的说法是不可达( 这里的不可达有别于5种引用状态:强可及,弱可及,软可及,虚可及,不可及 )</p> </li>     <li> <p>该对象被持有<br> 这里的被持有指的是被强引用持有,或者是软引用持有(在内存充裕时,软引用也会发生内存泄露)</p> </li>    </ul>    <p>什么对象会内存泄露?</p>    <p>发生内存泄露的2个条件中对象持有是必有条件,所以我们需要关注的引用中两种引用( 强引用和软引用 )和引用环境。</p>    <ul>     <li> <p>static 修饰持有<br> static修饰的成员变量,view,非静态内部类的静态实例,尤为值得关注的是 单例模式</p> </li>     <li> <p>长连接,持续性的</p> <p>数据库连接的关闭,android中动画是否及时关闭,观察者模式中注册对象是否及时取消注册</p> </li>     <li> <p>集合对象清理</p> <p>在此请参考ArrayList的clear方法</p> <pre>  <code class="language-java">@Override  public void clear() {   if (size != 0) {       Arrays.fill(array, 0, size, null);       size = 0;       modCount++;   }  }  public static void fill(Object[] array, int start, int end, Object value) {         Arrays.checkStartAndEnd(array.length, start, end);   for (int i = start; i < end; i++) {       array[i] = value;   }  }</code></pre> <p>如何查找内存泄露呢?敬请等待下一文</p> </li>    </ul>    <p> </p>    <p>来自:http://www.jianshu.com/p/56f008065246</p>    <p> </p>