判定对象是否存活算法
- 引用计数法
在对象中添加一个引用计数器,有地方引用这个对象的时候,值就加一,引用失效的时候就减一。
存在对象循环引用的时候,不能分析出对象是否可回收的问题。 - 可达性分析法
基本思想是通过一系统被称为“GC Root”的对象为起点,从这个起点向下搜索,搜索走过的路径称为引用链,当一个对象不再任何引用链上时,则说明这个对象是不可能再被使用的。
在Java语言中,GC Root包括以下几种对象:
1、虚拟机栈中引用的对象
2、本地方法栈中JNI引用的对象
3、方法区中类静态成员变量引用的对象
4、方法区中常量引用的对象
另外,在jdk1.2之后多了4中java引用类型,他们对垃圾回收也有一定影响;将引用分为了:强引用(Strong Reference)(即使内存不足也不会被回收)、软引用(Soft Reference)(内存不足时回收)、弱引用(Weak Reference)(不论内存是否足够,只要回收就会被回收)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。(详细信息点击查看)
垃圾回收算法
- 标记-清除算法
从根集合(GC Roots)开始进行扫描,标记存活的对象,标记完毕后,在扫描整个内存空间,回收未被标记的对象。
由于是直接回收对象,不涉及对象的移动,因此在存活对象较多的时候比较高效,但是会造成内存碎片,在后续内存分配的时候,可能会造成效率低下问题。 - 复制算法
把堆分成一个对象面和多个空闲面, 程序从对象面为对象分配空间,当对象满了,基于copying算法的垃圾收集就从根集合(GC Roots)中扫描活动对象,并将每个活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。
我们在前文说过堆可以分为Eden区,两个survivor区,和一个老年代区,每创建新对象都是在Eden区,且垃圾回收的时候基本上会回收完,那么复制算法就是针对两个survivor区的。 - 标记-整理算法
同标记-清除算法一样,不同的是,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。所以相比之下,虽增加了成本,但解决了内存碎片的问题。 - 分代收集算法
就是结合复制算法和标记-整理算法,在不同的‘代’上进行回收。
垃圾收集器
- Serial收集器(复制算法)
新生代单线程收集器,标记和清理都是单线程,优点是简单高效。是client级别默认的GC方式,可以通过-XX:+UseSerialGC来强制指定。 - ParNew收集器(复制算法)
新生代收集器,可以认为是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现 - Parallel Scavenge收集器(复制算法)
并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)。适合后台应用等对交互响应要求不高的场景。是server级别默认采用的GC方式,可用-XX:+UseParallelGC来强制指定,用-XX:ParallelGCThreads=4来指定线程数 - CMS(Concurrent Mark Sweep)收集器(标记-清除算法)
高并发、低停顿,追求最短GC回收停顿时间,cpu占用比较高,响应时间快,停顿时间短,多核cpu 追求高响应时间的选择。 - G1收集器(最牛的收集器)
详情