一、怎样回收
GC内部采用了引用计数法,只收集计数为0的对象
1、引用计数法:此对象有一个引用则+1,删除一个引用则-1;
缺点:(1)无法处理循环引用
(2)引用计数方法需要编译器配合,编译器需要为为这个对象生成额外代码。
因为这些缺点jvm实际并未采用引用计数。
2、根搜索算法:
设立若干根对象,若任何一个根对象到某个对象均不可到达时,则可以被回收。
Java语言中可以当做GC roots的有以下几种:
(1)虚拟机栈中的引用对象(方法的本地变量表)
(2)方法区中的类静态属性引用对象
(3)方法区中的常量引用的对象(声明为final的常量值)
(4)本地方法栈中JNI的引用对象(方法的本地变量表)
基于根搜索的算法主要有三种
1、标记/清除算法
当堆中的有效内存空间被耗尽,就会停止整个程序,进行
标记:遍历所有GC roots,将所有GC roots可达的对象标记为存活对象
整理:遍历所有对象,将没有标记的对象清除
缺点:效率比较低,还需要停止程序。清理出的空间是不连续的。
2、复制算法
将内存划分为两个区间,在任意时间点。所有动态分配的对象都只能分配在一个空间(活动空间)。
另一个为空闲空间。当有效内存空间耗尽,jvm停止程序,开始复制算法线程。jvm将所有活动对象复
制到空闲空间(严格按照内存地址依次排列)。与此同时GC线程将更新存活对象地址指向新的地址,
回收活动空间。
缺点:
浪费了一半空间,如果对象存活率很高那么效率低下。
3、标记整理算法
标记:与标记清算法一致。
整理:将所有存活对象按照地址依次排列,将末位置以后的地址全部回收。
缺点:效率不高
二、那些对象可以被回收
分代搜集算法是针对Java堆中的对象设计的。
1、存活时间非常短:方法的局部变量,循环内的临时变量等...(在Java的堆)适合复制算法
10%空闲区10%活动区80%分配新对象
2、存活时间较长:缓存对象、数据库连接对象、单例对象等...(在Java的堆)
存放在老年代(采用标记整理和标记清除算法)
什么情况会导致对象从新生代变为来年代呢?
答:1、新生代成员,每次GC都会活下来
2、新生代存活对象超过内存10%就会被放入老年代。
3、一直存活:String池中的对象(享元模式),加载过的类信息等...(在Java的方法区)
不灭对象存放在方法区(存在hotspot虚拟机)也被称为永久带。
(采用标记整理和标记清除算法)
三、回收的时机
GC回收时大部分都是回收新生代的内容。GC按照回收区域分为两类:
普通GC:只针对新生代区域的GC
全局GC:针对老年代的GC,偶尔还会伴随着对新生代、和老年代的GC。