垃圾回收机制garbage collection

内存管理

Java的内存管理一般指对象管理,包括:

对象空间的分配:new关键字创建对象。

对象空间的释放:将对象赋值null即可。

垃圾回收器作用:发现无用对象【没有任何变量引用该对象】并将其占用的内存空间回收。

垃圾回收算法

1.引用计数法

堆内存中每个对象被引用一次,计数加一,引用变量变为null,则计数减一,直至计数为0变为空变为无用对象。

优点:算法简单。

缺点:循环引用的无用对象无法识别。

示例:

package com.itcode.demo3;  

/** 
 * @Auther: 成都码到功成学员 
 * @Description: 
 */  
public class TestObject {  
    String name;  
    TestObject oo;  
    public static void main(String[] args) {  
        TestObject o = new TestObject();  
        TestObject t = new TestObject();  
        o.oo = t;  
        t.oo = o;  
        o = null;  
        t = null;  
    }  
}

2.引用可达法(根搜索算法)

把所有引用关系看作一张图,从一个根节点GC ROOT出发,寻找对应的引用节点以及其节点的引用节点,当整个寻找流程完毕,剩余没有找到(引用)的节点就是无用的对象。

分代垃圾回收机制

原因:不同对象的生命周期不一致,要分别采用不同的回收算法,提高回收效率。

对象分为三种状态:年轻代、年老代、持久代。JVM堆内存中分为Eden、Survivor和 Tenured/Old 空间。年轻代(Eden,Survivor),年老代(Tenured/Old)。

对象状态

  • 1. 年轻代

存放:所有新生成的对象首放位置。

目标:尽可能快速收集掉那些生命周期短的对象,对应的是Minor GC。

概述:Minor GC采用效率较高的复制算法、频繁的操作清理年轻代内存,但是会浪费内存空间。年轻代区域存放满对象后,就将对象存放到年老代区域。

Eden存放:从未通过垃圾回收的新对象。

Survivor存放:垃圾回收(小于15次)后仍然有用的对象,循环存放。

  • 2. 年老代

存放:一些生命周期较长的对象,年轻代中经历了n(默认15)次垃圾回收后仍然存活的对象。每次经过回收存活下来的对象年龄会加1。老年代中启动GC的频率较低,回收的效率也比较低。

概述:当对象装满Old区,会同时启动Major GC和Full GC(全量回收)全面清理年轻代区域和年老代区域。

  • 3. 持久代

存放静态文件,如Java类、方法等(类信息、常量、静态变量、即时编译器编译后的代码)。持久代对垃圾回收没有显著影响。

回收器介绍

Minor GC:

作用:清理年轻代。

概述:Eden区满了就会触发一次Minor GC。清理无用对象,将有用对象复制到“Survivor1”、“Survivor2”区(两个区大小空间也相同,同一时刻Survivor1和Survivor2只有一个在用,一个为空)。

Major GC:

作用:清理年老代区域。

Full GC:

作用:清理年轻代、年老代区域。

概述:成本较高,会影响性能。性能优化主要是优化Full GC。

垃圾回收过程分析

  • 1.绝大多数新对象放在Eden区。

  • 2.满了之后【不能创造对象】调用Minor GC清理无用对象,把有用对象放到survivor1或者survivor2,假如放在survivor1,同时把Eden清空。

  • 3.当Eden再次满之后。先在survivor1调用Minor GC清理无用对象,把有用对象放到survivor2,。同时在Eden调用Minor GC清理无用对象,把有用对象放到survivor,清空Eden。

  • 4.当survivor区域循环存放超过15次之后调用Minor GC把仍然有用的对象存放在Old区。

  • 5.当Old区的对象达到一定的比例会启动Major GC清理一下。

  • 6.当Old区满之后调用Full GC清理年轻代和年老代区域(包括Eden、Survivor、Old)。

Full GC被调用的时机

年老代区写满

持久代区写满

程序里写System.gc(),不建议使用,系统自己知道调用。

一次GC后Heap堆各域分配策略动态变化。

开发中容易造成内存泄露(系统奔溃)的操作

暂时不讲,很多知识要后面才学到,等工作中用到再回头看。

    1. 创建大量无用对象:比如使用String而非StringBuilder拼接大量拼接字符串。

String s = "";  
for(int i=0; i<10000; i++){  
    s+=i;//相当于创建10000个String对象  
}
  • 2 静态集合类的使用:如HashMap、Vector、List,静态变量的生命周期和应用程序一致导致所有对象Object不能被释放。

  • 3 各种连接对象(IO流对象、数据库连接对象、网络连接对象)未关闭,这些连接对象属于物理连接,不使用的时候请及时关闭。(开发中不关闭运行经常会出现bug,一定要注意)

  • 4 监听器的使用:释放对象时没有删除相应监听器。

要点:

  • 1 程序员无权调用垃圾回收器。

  • 2 调用System.gc()只是通知JVM,并非运行垃圾回收器,而且会启动Full GC,影响系统性能(前面章节有讲,请仔细看)。

  • 3 finalize()是释放对象或资源的方法,建议少用。

Last updated

Was this helpful?