GC
首先 垃圾回收算法并非Java独创,而是在Java很早之前就已经出现了的。
需要考虑三个问题
那些内存需要回收
什么时候回收
如何回收
那些内存需要回收
在开发中存在两种判断方式
计数算法
在对象中设置一个计数器,作为引用次数。
引用一次就在这个计数器上 + 1
结束引用就在计数器中 - 1
确实是一个比较简单高效的办法,但是无法去判断孤立的对象集合
或自引用的对象集合
对象A中包含对象B
对象B中包含对象A
导致A的计数器恒定 1 B的计数器也是恒定1
可达性算法
为了解决上述自引用的问题,Java采用的也是这种可达性算法
虚拟机会定义一个树形结构 GC Roots 把对象进行连接 查看对象的可达性
如果不可达 就认为对象是无法访问的 是可回收的对象
就像上图中 对象 B,C,D 虽然都互相引用,但是因为没有与GCRoots的连接 所以也算作是没有用的对象
会被进行回收
GC Roots
在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
本地方法栈中 JNI(Native方法)引用的对象
Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
所有被同步锁(synchronized关键字)持有的对象。
反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
根据用户所选用的垃圾收集器以及当前回收的内存区域不 同,“临时性”地加入的其他对象。
引用
上述多次提到引用,在现代的 Java 版本中 对 引用概念进行扩充
分为以下几种类型
强引用 就是引用-赋值,类似
Object test = new Object();
这就是一个强引用只要引用关系还在,GC就永远不会回收这些对象
软引用 用来描述一些,有用,但是用途不大的对象类型
在内存告急的情况下,触发了两次GC才会把软引用的对象进行回收
弱引用 只能存活到下次GC回收前
虚引用 不会对回收产生任何影响,他的作用是在被回收时输出一个日志
方法区回收
方法区在不同JVM实现也不同,部分JVM也未实现方法区的数据回收。部分JVM的方法区在元空间。
要回收方法区的数据要有三个条件:
该类所有实例都被回收,Java堆中不存在该类的任何派生子类的实例。
加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换加载类的场景,重加载场景OSGI JSP 等,否则是很难达成的。
该类对应的 java.lang.Class 对象没有被任何地方引用,无法在任何地方通过反射的方式访问该类的方法。
参与讨论
(Participate in the discussion)
参与讨论