天天看点

回顾GC是如何判断哪个对象应该被回收问题

一 概述

Java程序中,当一个对象没有被其它对象引用时,则该对象对于虚拟机而言就应该被回收的对象,其占用的内存空间需要被释放,同时对象也会被销毁。

二 判断对象应该被回收的具体算法

1. 引用计数算法

该算法通过判断对象的引用数量来决定对象是否可以被回收,在此机制下,堆中每个对象都存在一个引用计数器,当一个对象创建后被分配一个引用之后则对应的引用计数器加1,当引用完成后则引用计数器相应的减1,当某个对象的引用计数器为0的时候后,则会被虚拟机作为垃圾进行回收,并释放其所占用的内存空间。

优点:引用计数算法的执行效率高,程序执行所受的影响较小。

缺点:引用计数算法无法检测出循环引用(父对象引用子对象,子对象引用父对象),其内存空间无法被回收,从而导致内存泄漏。

2. 可达性分析算法

该算法通过判断对象的引用链是否可达来决定对象是否会被作为垃圾进行回收。

该算法是从离散数学的图论中引入,将程序的所有引用作为一张图,通过将一些GC Roots对象作为起始点,从这些结点开始向下搜索,搜索所做过的路径被称为引用链,如果某个GC Roots没有与任何引用链相连,则称GC Roots到该对象为不可达,此时该对象可以作为垃圾进行回收,然后释放其所占据的内存空间。

三 GC Roots实例

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数,局部变量,临时变量等。
  • 在方法区中类静态属性引用的对象,如Java类的引用类型静态变量。
  • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
  • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象,。
  • 所有别同步锁(synchronized关键字)所持有的对象。
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointException,OutOfMemoryError)等,还有系统类加载器。