欢迎光临北大青鸟佛山华大校区

我的位置: 首页 >>Java GC 的那些事(1)

Java GC 的那些事(1)

2018-09-29

来源:

  Java GC 的那些事(1)

  前言

  与C语言不同,Java内存(堆内存)的分配与回收由JVM垃圾收集器自动完成,这个特性深受大家欢迎,能够帮助 程序员 更好的编写代码,本文以HotSpot虚拟机为例,说一说Java GC的那些事。

  Java堆内存

  在 JVM内存的那些事 一文中,我们已经知道Java堆是被所有线程共享的一块内存区域,所有对象实例和数组都在堆上进行内存分配。
  新生代

  新生代由 Eden 与 Survivor Space(S0,S1)构成,大小通过-Xmn参数指定,Eden 与 Survivor Space 的内存大小比例默认为8:1,可以通过-XX:SurvivorRatio 参数指定,比如新生代为10M 时,Eden分配8M,S0和S1各分配1M。

  Eden:希腊语,意思为伊甸园,在圣经中,伊甸园含有乐园的意思,根据《旧约·创世纪》记载,上帝耶和华照自己的形像造了男人亚当,再用亚当的一个肋骨创造了一个女人夏娃,并安置他们住在了伊甸园。

  大多数情况下,对象在Eden中分配,当Eden没有足够空间时,会触发一次Minor GC,虚拟机提供了-XX:+PrintGCDetails参数,告诉虚拟机在发生垃圾回收时打印内存回收日志。

  Survivor:意思为幸存者,是新生代和老年代的缓冲区域。

  当新生代发生GC(Minor GC)时,会将存活的对象移动到S0内存区域,并清空Eden区域,当再次发生Minor GC时,将Eden和S0中存活的对象移动到S1内存区域。

  存活对象会反复在S0和S1之间移动,当对象从Eden移动到Survivor或者在Survivor之间移动时,对象的GC年龄自动累加,当GC年龄超过默认阈值15时,会将该对象移动到老年代,可以通过参数-XX:MaxTenuringThreshold 对GC年龄的阈值进行设置。

 
  如何判断对象是否存活

  GC动作发生之前,需要确定堆内存中哪些对象是存活的,一般有两种方法:引用计数法和可达性分析法。

  1、引用计数法

  在对象上添加一个引用计数器,每当有一个对象引用它时,计数器加1,当使用完该对象时,计数器减1,计数器值为0的对象表示不可能再被使用。

  引用计数法实现简单,但不能解决对象之间相互引用的问题。

  public class GCtest {    private Object instance = null;    private static final int _10M = 10 * 1 << 20;    // 一个对象占10M,方便在GC日志中看出是否被回收    private byte[] bigSize = new byte[_10M];    public static void main(String[] args) {        GCtest objA = new GCtest();        GCtest objB = new GCtest();        objA.instance = objB;        objB.instance = objA;        objA = null;        objB = null;        System.gc();    }}

  通过添加-XX:+PrintGC参数,运行结果:

  [GC (System.gc()) [PSYoungGen: 26982K->1194K(75776K)] 26982K->1202K(249344K), 0.0010103 secs]

  从 GC日志 中可以看出objA和objB虽然相互引用,但是它们所占的内存还是被垃圾收集器回收了。

  2、可达性分析法

  通过一系列称为 GC Roots 的对象作为起点,从这些节点开始向下搜索,搜索路径称为 引用链,以下对象可作为GC Roots:

  本地变量表中引用的对象

  方法区中静态变量引用的对象

  方法区中常量引用的对象

  Native方法引用的对象

  当一个对象到 GC Roots 没有任何引用链时,意味着该对象可以被回收。

  在可达性分析法中,判定一个对象objA是否可回收,至少要经历两次标记过程:

  1、如果对象objA到 GC Roots没有引用链,则进行标记。

  2、如果对象objA重写了finalize()方法,且还未执行过,那么objA会被插入到F-Queue队列中,由一个虚拟机自动创建的、低优先级的Finalizer线程触发其finalize()方法。finalize()方法是对象逃脱死亡的机会,GC会对队列中的对象进行标记,如果objA在finalize()方法中与引用链上的任何一个对象建立联系,那么标记时,objA会被移出即将回收集合。

  看看具体实现

  public class FinalizerTest {    public static FinalizerTest object;    public void isAlive() {        System.out.println(I'm alive);    }    @Override    protected void finalize() throws Throwable {        super.finalize();        System.out.println(method finalize is running);        object = this;    }    public static void main(String[] args) throws Exception {        object = new FinalizerTest();        // ,finalize方法会自救        object = null;        System.gc();        Thread.sleep(500);        if (object != null) {            object.isAlive();        } else {            System.out.println(I'm dead);        }        // 执行,finalize方法已经执行过        object = null;        System.gc();        Thread.sleep(500);        if (object != null) {            object.isAlive();        } else {            System.out.println(I'm dead);        }    }}

  执行结果:

  method finalize is runningI'm aliveI'm dead

  从执行结果可以看出:

  发生GC时,finalize方法的确执行了,并且在被回收之前成功逃脱;

  发生GC时,由于finalize方法只会被JVM调用一次,object被回收。

  当然了,在实际项目中应该尽量避免使用finalize方法。

  Java GC 的那些事(1)

  Java GC的那些事(2)

开班信息

开班课程 人数 了解详情
高端名企定向委培班 剩余名额3 课程介绍
ACCP8.0软件培训班 剩余名额8 课程介绍
短期冲刺班 剩余名额2 课程介绍
项目精英班 剩余名额1 课程介绍
UI课程重点培训班 剩余名额6 课程介绍
WEB开发精英班 剩余名额2 课程介绍
JAVA特招班 剩余名额10 课程介绍

免费试听

试听课程 了解详情
高端名企定向委培班 试听详情
ACCP8.0软件培训班 试听详情
短期冲刺班 试听详情
项目精英班 试听详情
UI课程重点培训班 试听详情
WEB开发精英班 试听详情
JAVA特招班 试听详情

姓名:

电话:

最新就业

姓名 就业岗位 就业企业
何伟煊 java工程师 金政信息科技
张雅涵 前端工程师 国贸集团股份有限公司
张默 项目组长 极宇舟天有限公司
张婧涵 前端工程师 大族激光有限公司
张洪文 运维工程师 诚迈科技有限公司
王玥婷 java技术顾问岗位 百纳威尔有限公司
王鸿轩 Java开发岗位 爱卡智能
邓安志 软件开发工程师 美的集团
何浚宏 软件开发课程工程师 东和科技有限公司
黄隆 软件开发顾问 建发股份公司
刘应琴 软件开发工程师 国美集团
刘雨林 java工程师 唯品会科技有限公司
彭子昂 Java开发 爱卡智能有限公司

在线答疑更多++

热门专题更多++

广东省佛山市禅城区佛山大道北143号北大青鸟华大校区

地址:广东省佛山市禅城区佛山大道北143号

电话:4006-989-522  0757-88726000

网址: www.bdqnfshd.com

佛山校区乘车路线:张槎路口站、白燕公园站、轻工路口站、金沙新城南门站

  • 技术支持:网络公司易网互联
  • 备案号:粤ICP备17103049号-6
  • 版权所有:佛山市禅城区华大计算机职业技能培训学校

北大青鸟华大校区公众平台

佛山北大青鸟