垃圾回收主要集中于 java 堆和方法区中
借鉴的这儿
判断对象存活:
1. 引用计数:给每一个对象设定一个应用计数属性,新增引用计数加一,释放应用计数减一,当到达0之后进行回收。
缺点:如果有下面这样一段代码,最后a,b的计数都不为0,导致无法回收。所以无法解决对象相互循环引用的问题。
A a=new A();//a->1
B b=new B();//b->1
a=b;//b->2
b=a;//a->2
a=null;//a->1
b=null;//b->1
2. 可达性分析:从GC Roots开始搜索,通过引用链进行搜索形成一张连通的图,此时,如果没有被搜索到的对象,则判定为回收对象。
可以作为roots的对象:
- 方法区中的静态变量和常量引用的对象
- 本地栈中的JNI引用的对象
- 虚拟机中引用的对象
垃圾收集算法
1. 标记 -清除算法
先标记出所有需要回收的对象,然后对对象统一回收。
缺点:标记和清除过程效率不高。清楚后会产生需要不连续的内存碎片,如果下一次需要分配一个较大的连续空间,则会提前进行一次垃圾回收。费时,费空间。
2. 复制算法
将内存等分为两块,每次使用其中一块,然后一次使用完之后,回收垃圾,并将这一块复制到另外一块(按顺序分配内存)。然后清理到这一块内存上的对象。
优点:不会产生碎片化。
缺点:内存打折扣,每次只能使用一半的内存。会将长期存在的对象多次复制,影响效率。
3. 标记-压缩算法
在标记-清除算法的标记之后添加一个压缩的过程,将所有存活对象向一端移动,然后再清除所有端边界意外的内存空间。
4. 分代收集算法
把java堆分成新生代和老年代,对于新生代,每一个对象存活的时间都比较短,每次垃圾回收都有许多需要回收,那么可以采用复制算法,只需要复制少量存活的对象即可。而对于老年代,存活率较高,没有额外空间对他们进行分配担保,就必须使用标记清除或者标记压缩算法。方法区为永久代,方法和老年代一样。
垃圾收集器
1. Serial收集器
串行收集器只使用一个线程回收,可能会产生较长的停顿,新生代复制算法,老年代使用标记整理算法
参数控制: -XX:+UseSerialGC 串行收集器
2. ParNew收集器
串行收集器的多线程版本。新生代并行,老年代串行;新生代复制算法、老年代标记-压缩
-XX:+UseParNewGC ParNew收集器
-XX:ParallelGCThreads 限制线程数量
3. Parallel收集器
Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。可以通过参数来打开自适应调节策略,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量;也可以通过参数控制GC的时间不大于多少毫秒或者比例;新生代复制算法、老年代标记-压缩
参数控制: -XX:+UseParallelGC 使用Parallel收集器+ 老年代串行
4. Parallel Old 收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。这个收集器是在JDK 1.6中才开始提供。提供了老年代并行的能力。
参数控制: -XX:+UseParallelOldGC 使用Parallel收集器+ 老年代并行
5. CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用都集中在互联网站或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。
从名字(包含“Mark Sweep”)上就可以看出CMS收集器是基于“标记-清除”算法实现的,它的运作过程相对于前面几种收集器来说要更复杂一些,整个过程分为4个步骤,包括:
-
初始标记(CMS initial mark)
-
并发标记(CMS concurrent mark)
-
重新标记(CMS remark)
-
并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行。老年代收集器(新生代使用ParNew)
优点: 并发收集、低停顿
缺点: 产生大量空间碎片、并发阶段会降低吞吐量
参数控制:
-XX:+UseConcMarkSweepGC 使用CMS收集器
-XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
-XX:+CMSFullGCsBeforeCompaction 设置进行几次Full GC后,进行一次碎片整理
-XX:ParallelCMSThreads 设定CMS的线程数量(一般情况约等于可用CPU数量)
6. G1收集器
将一个内存区域等分为好多个内存区域,每个区域并发标记,若整个区域中的对象都被回收,则直接回收这个区域,再标记,清除,然后将存活对象拷贝到新的区域,并发清空回收区域并把它返回到空闲区域链表中。