Java 虚拟机 其他相关博客
深入理解 Java 虚拟机 学习:Java虚拟机内存区域
深入理解 Java 虚拟机 学习:对象访问
引用资料地址
垃圾收集算法与垃圾收集器
Java常见面试题—GC垃圾收集器
7种垃圾收集器
《 深入理解 Java 虚拟机:JVM高级特性与最佳实践》
介绍
GC垃圾收集,Java提供的GC可以自动监测对象是否超过作用域从而达到自动回收内存的目的。
垃圾回收可有效使用内存和防止内存泄露。垃圾回收器通常是作为一个单独的低优先级线程运行,不可预知的情况下对内存堆中已死亡或长久无使用的对象进行清除和回收。回收机制:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。
引用计数算法
介绍:给每一个对象添加一个引用计数器,当有引用指向对象时,计数器加一,引用移除时,计数器减一,当计数器为0时,说明对象未被引用,可以回收
存在问题:两个对象互相引用,此时不会被回收。
使用:java虚拟机不采用
根搜索算法
介绍:通过一系列的名为“GC Roots”的对象作为起点,从这些节点向下搜索,经过的路径称为引用链,当一个对象没有引用链即是可回收状态。
java语言中的GC Roots 的对象包括:
1.虚拟机栈中的引用对象
2.方法区中的类静态属性引用的对象
3.方法区常量引用的对象
4.本地方法栈中JNI的引用对象
使用:java虚拟机采用
注意:所有对象的finalize()方法只会执行一次,如果对象面临下一次回收,它的 finalize() 方法不会被再次执行,自救行动失败
介绍:标记-清除算法分为两个阶段为标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间
缺点:
1.效率问题:标记和清楚过程的效率都不高
2.空间问题:标记清除之后会产生大量不连续的内存碎片,导致当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
介绍:为了解决标记 - 清除算法的缺陷,复制算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题
优点:每次都是对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效
缺点:这种算法的代价是将内存缩小为原来的一半,代价高昂
介绍:为了解决复制算法的缺陷,充分利用内存空间,提出了标记-整理算法。该算法标记阶段和标记-清除算法一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。
介绍:当前商业虚拟机的垃圾收集都采用分代收集算法,根据对象的存活周期的不同将内存划分为几块。一般是把 Java 堆分为新生代和老年代,根据各个年代的特点采用最适合的收集算法。
备注:在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,选用复制算法。在老年代中因为对象存活率搞,没有额外空间对他进行分配担保,就必须使用标记-清除算法或标记-整理算法来进行回收
注意:在堆区之外还有一个代就是永久代(Permanet Generation),它用来存储class类、常量、方法描述等。对永久代的回收主要回收两部分内容:废弃常量和无用的类。
介绍:吞吐量就是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比例,而高吞吐量可以高效率地利用 CPU 时间,尽快地完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务
公式:吞吐量就是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比例,即 吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间),虚拟机总共运行了 100 分钟 ,其中垃圾收集花费 1 分钟,那吞吐量就是 99%
介绍:GC收集算法是内存回收的方法论,垃圾收集器是内存回收的具体实现。Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商、不同版本的虚拟机所提供的垃圾收集器都可能会有很大差别,并且一般都会提供参数供用户根据自己应用的特点和要求组合出各个年代所使用的收集器。
注意:如果两个收集器之间存在连线,就说明它们可以搭配使用
介绍:新生代(年轻代)收集器,单线程进行垃圾回收,回收时会导致Stop The World,用户进程停止,可以和Serial Old、CMS组合使用
算法:复制算法
线程:单线程收集器
优点:简单而高效
缺点:它在进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束。比如电脑运行一小时就会暂停响应五分钟
介绍:ParNew 收集器就是 Serial 收集器的多线程版本,它也是一个新生代收集器。除了使用多线程进行垃圾收集外,其余行为包括 Serial 收集器可用的所有控制参数、收集算法(复制算法)、Stop The World、对象分配规则、回收策略等与 Serial 收集器完全相同,两者共用了相当多的代码。
算法:收集算法(复制算法)
线程:多线程收集器
优点:除了 Serial 收集器外,目前只有它能和CMS收集器(Concurrent Mark Sweep)配合工作。CPU 的数量增加时,它对于 GC 时系统资源的有效利用是很有好处的,它默认开启的收集线程数与 CPU 的数量相同,在 CPU 非常多的情况下可使用 -XX:ParallerGCThreads 参数设置
缺点:ParNew 收集器在单CPU的环境中绝对不会有比 Serial 收集器有更好的效果,甚至由于存在线程交互的开销,该收集器在通过超线程技术实现的两个CPU的环境中都不能百分之百地保证可以超越
介绍:Parallel Scavenge 也是一个新生代收集器,看上去和 ParNew 收集器差不多,区别在于 Parallel Scavenge 的 目标是达到一个可控制的吞吐量,Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的 -XX:MaxGCPauseMillis 参数及直接设置吞吐量大小的 -XX:GCTimeRatio 参数
算法:复制算法
线程:多线程收集器
关于吞吐量:
优点:Parallel Scavenge 通过控制吞吐量,从而达到可以高效率地利用 CPU 时间,尽快地完成程序的运算任务
缺点:使用多线程进行垃圾回收,回收时会导致Stop The World
介绍:Serial Old 收集器是 Serial 收集器的老年代版本,这个收集器主要意义也就是被 Client 模式下的虚拟机使用
线程:单线程收集器
算法:标记 - 整理算法,会对垃圾回收导致的内存碎片进行整理
两大用途:
介绍:Parallel Old 收集器是 Parallel Scavenge 收集器的老年代版本,这个收集器是在 JDK 1.6 中才开始提供的,在此之前,新生代的 Parallel Scavenge 收集器一直处于比较尴尬的状态。原因是,如果新生代选择了 Parallel Scavenge 收集器,老年代除了 Serial Old 收集器外别无选择。所以在 Parallel Old 诞生以后,“吞吐量优先”收集器终于有了比较名副其实的应用组合,在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器。
线程:多线程收集器
算法:标记 - 整理算法,会对垃圾回收导致的内存碎片进行整理
介绍:CMS 收集器是 一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的 Java 应用都集中在互联网站或 B/S 系统的服务端上,这些应用都非常重视服务的响应速度
线程:
算法:标记 - 清除,可以通过设置参数在垃圾回收时进行内存碎片的整理
运作过程:
优点:并发收集、低停顿,因此CMS收集器也被称为并发低停顿收集器 。适合于对响应时间要求高的系统
缺点:
介绍:G1(Garbage-First)收集器是当今收集器技术发展最前沿的成果之一,它是一款面向服务端应用的垃圾收集器,HotSpot开发团队赋予它的使命是(在比较长期的)未来可以替换掉JDK 1.5中发布的CMS收集器
算法:标记 - 整理算法,也就是说不会产生空间碎片,对长时间运行的应用系统来说非常重要
特点:
收集器 | 线程 | 新生代/老年代 | 算法 | 优先 | 适用场景 |
---|---|---|---|---|---|
Serial 收集器 | 串行 | 新生代 | 复制算法 | 响应速度优先 | 单CPU环境下的Client模式 |
ParNew 收集器 | 并行 | 新生代 | 复制算法 | 响应速度优先 | 多CPU环境时在Server模式下与CMS配合 |
Parallel Scavenge 收集器 | 并行 | 新生代 | 复制算法 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
Serial Old 收集器 | 串行 | 老年代 | 标记-整理 | 响应速度优先 | 单CPU环境下的Client模式、CMS的后备预案 |
Parallel Old 收集器 | 并行 | 老年代 | 标记-整理 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
CMS 收集器 | 并发 | 老年代 | 标记-清除 | 响应速度优先 | 集中在互联网站或B/S系统服务端上的Java应用 |
G1 收集器 | 并发 | All | 标记-整理+复制算法 | 响应速度优先 | 面向服务端应用,将来替换CMS |