⑴背景

Java堆和方法区实现类所需内存是不一样的,每个方法的多分支需要的内存也可能不一样,我们只有在运行期间才能制动创建哪些对象。这部分内存分配与回收都是动态的,而垃圾回收器所关注的就是这些这部分内存。

⑵基本垃圾回收算法

①引用计数法:给每个对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,当引用失效时,计数器就减1,任何时刻计数器为0的对象是不可能被使用的。

引用计数法简单易实现,但判定效率也很高,在大部分情况下式不错的算法。但主流Java虚拟机都没有使用引用计数器来管理内存,主要原因是他很难解决对象之间的循环引用问题

例如:ObjA.instance = ObjB,ObjB.instance = ObjA,除此之外这两个对象再无其他引用。实际上这两个对象没有别其他对象应用,但是引用计数器无法通知GC来回收它们。

②可达性分析:在Java中是使用可达性分析来判定对象是否存活。算法思路就是通过一系列称为“GC Roots”的队形作为起点,从这些节点向下搜索搜索所走的路径称为“引用链”,当一个对象

到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

如图:

③标记-清除算法:标记-清楚算法分为两个阶段,首先标记处所需的回收对象,在标记完成之后统一回收所有标记的对象,后面的算法都是基于该算法进行改进。该算法有两大不足之处:一是效率低,标记与清除的两个过程效率不高;二是空间问题,标记清除之后会产生大量的不连续内存碎片,空间碎片过多会导致以后程序运行时需要分配较大对象时,无法找到足够的连续内存,而不得不提前触发一次垃圾收集动作。

如图(图片来自网络):

④复制算法:复制算法常用于新生代。将可用内存按容量划分为大小相等的两块,每次使用其中一块,当这一块用完之后,仍存活的对象赋值到另一块上,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个搬去进行内存回收,内存分配时不需要考虑内存不连续,碎片的情况,只需要按顺序分配内存即可。但是该算法的代价是内存缩小为原来的一半。属于用空间换时间。

在新生代的对象中98%是“朝生夕死”的,所以并不需要按照1:1的比例划分空间,而是将内存分为一块较大的Eden空间和两块较小的Suvivor空间,每次使用Eden和其中一个Survivor,当回收时,将Eden和Suvivor中还存活的对象一次性地复制到另一块Survivor空间上,然后清楚掉Eden和刚才用过的Survivor空间。

⑤标记-整理:标记-整理算法常用于老年代,如果在内存中如果对象的存活率较高,使用复制算法效率就会非常低下。于是根据老年代的特点出现了“标记-整理”算法,其标记过程与“标记-清除”算法一样,后续步骤不是直接就对可回收对象进行清除,而是让所有存活的对象移动到一端,然后直接清理掉边界以外的内存。

如图(图片来自网络):

⑥分代收集算法:根据对象存活周期分为新生代和老年代,然后根据各自年代特点使用不同算法。在新生代中,每次垃圾收集时发现有大批对象死去,存货量较小,这时候使用复制算法就非常合适。在老年代中,对象的存活率较高,使用复制算法显然不划算,这时候就选择采用“”“标记-整理”算法去实现内存回收。

⑶垃圾收集器

HotSpot虚拟机垃圾收集器(图片来自网络)

①Serial收集器:该收集器是一个单线程的收集器,只会使用一个CPU或一条收集线程去完成垃圾收集,而且在进行垃圾收集时,其他工作线程都必须暂停。

②ParNew收集器:ParNew是Serial收集器的多线程版本。

ParNew收集器是Server模式下的虚拟机中首选的新生代收集器,其中一个与性能无关但很重要的原因是,除了Serial收集器外,目前只有它能够与CMS收集器配合工作,在单CPU环境中效果不比Serial,但但当CPU非常多的环境下,ParNew的优势就体现出来了。

③ CMS收集器:以获取最短回收停顿时间为目标的收集器,CMS收集器基于“标记-清除”算法实现。

过程分为4个部分:

Ⅰ 初始标记:初始标记仅仅只是标记GC Roots所能够关联到的对象(可达性分析)

Ⅱ 并发标记:根搜索(GC Roots Tracing)算法基本原理是:GCRoot对象作为起始点(根)。如果从根到某个对象是可达的,则该对象称为“可达对象”(存活对象,不可回收对象)。

Ⅲ 重新标记:重新标记阶段是为了修正并发标记期间因用户程序运作而导致标记产生变动的那一部分对象的标记记录。(边打扫卫生边仍纸屑)

Ⅳ 并发清除:并发将可回收内存全部回收。

其中需要“Stop The World”的有Ⅰ,Ⅲ过程

CMS缺点:

Ⅰ.CPU资源非常敏感,在面向并发程序时,CMS虽然不会导致用户线程停顿,但仍然会因为并发标记或并发清除占用了部分线程,导致应用程序变慢,总吞吐量降低。

Ⅱ.CMS无法处理浮动垃圾,由于CMS并发清理阶段用户线程仍在运行着,伴随程序运行,自然还会有新的垃圾不断产生,这一部分垃圾出现在标记标记过程之后,CMS无法在当次集中处理它们,只能留到下一次GC再处理.

Ⅲ.CMS基于“标记-清除”算法,该算法会产生大量的空间碎片,会出现老年代空间剩余,但无法找到连续的空间去分配当前对象,就必须提前触发一次Full GC.

④G1收集器:G1收集器是目前前沿收集器技术之一,到了JDK7u4才达到了商用程度

G1收集器所具备的特点:

Ⅰ.并发与并行:G1具有CMS一样多线程操作能力,G1能利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然能够通过并发方式让Java线程继续执行。

Ⅱ.分代收集:G1不需要其他收集器配合就能够独立管理整个GC堆,但他能够使用不同的方式去处理新创建对象和已存活一段时间对象、熬过多次的旧对象都有自己的处理方法。

Ⅲ.空间整合:CMS基于“标记-清除”,缺点是出现许多不连续内存,而G1则基于“标记-整理”,从局部(两个Region)上看基于“复制”算法,G1运行期间不会产生大量空间碎片,收集后能提供规整的可用内存空间,在分配大对象时不会由于找不到可用的连续内存而出发下一次GC。

Ⅳ.可预测停顿:G1与CMS不同,G1除了追求低停顿以外,还能建立可预测的停顿时间模型。

更详细:http://blog.csdn.net/renfufei/article/details/41897113

Java虚拟机之GC的更多相关文章

  1. java虚拟机(十三)--GC调优思路

    GC调优对我们开发人员来说,如果你想要技术方面一直发展下去,这部分内容的了解是必不可少的,jvm对于工作.面试来说都很重要,GC调优的问题 更是重中之重,因为是对你jvm学习内容的实践,知识只有应用实 ...

  2. java虚拟机之GC(转)

    垃圾回收主要内容: 1. 那些内存需要回收? 2. 什么时候回收? 3. 如何回收? 垃圾回收主要针对运行时数据区那些区域? 运行时数据区的线程私有区域有:虚拟机栈,本地方法栈,程序计数器等: 栈中的 ...

  3. Java 虚拟机枚举 GC Roots 解析

    JVM 堆内存模型镇楼. 读<深入理解 Java 虚拟机>第三章GC算法,关于 GC Roots 枚举的段落没说透彻,理解上遇到困惑.因此对这点进行扩展并记录,发现国内各种博客写来写去都是 ...

  4. java虚拟机(十一)--GC日志分析

    GC相关:java虚拟机(六)--垃圾收集器和内存分配策略 java虚拟机(五)--垃圾回收机制GC 打印日志相关参数: -XX:+PrintGCDetails -XX:PrintGCTimestam ...

  5. 深入理解java虚拟机,GC参考手册

    深入理解java虚拟机 一.<深入理解Java虚拟机> 1.第2章 Java内存区域与内存溢出异常 2.第3章 垃圾收集器与内存分配策略 3.第4章 虚拟机性能监控与故障处理工具 4.第5 ...

  6. Java虚拟机:GC算法深度解析

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 在前面的文章里介绍了可达性分析算法,它为我们解决了判定哪些对象可以回收的问题,接下来就该我们的垃圾收集算法出场了.不同的垃圾收集算法有各自 ...

  7. 深入理解Java虚拟机,gc输出参数

    https://blog.csdn.net/qq_21383435/article/details/80702205

  8. java虚拟机(十二)--可视化工具分析GC日志

    在上篇博客中,我们学习了Parallel.CMS.G1三种垃圾收集器的日志格式,本次我们通过工具去分析日志,会更加的直观 日志格式博客地址:java虚拟机(十一)--GC日志分析 GCeasy: 这是 ...

  9. Java虚拟机-垃圾收集器

    垃圾收集器(Garbage Collection, GC)的诞生引导出了三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 对于线程独占的三个区域(程序计数器.虚拟机栈.本地方法栈)不用过多的 ...

随机推荐

  1. DirectX:函数可以连接任意两个filter

    函数可以连接任意两个filter HRESULT ConnectFilters( IBaseFilter *pSrc, IBaseFilter *pDest ) { IPin *pIn = 0; IP ...

  2. 【原】Java学习笔记026 - 集合

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 需求:从三国演义中 ...

  3. 对维数组排序 array_multisort()的应用

    PHP允许在多维数组上执行一些比较复杂的排序--例如,首先对一个嵌套数组使用一个普通的关键字进行排序,然后再根据另一个关键字进行排序.这与使用SQL的ORDER BY语句对多个字段进行排序非常相似.为 ...

  4. css样式--表格

    1.示例源码 <!DOCTYPE html><html><head><meta charset="utf-8"> <title ...

  5. 【转载】Java并发编程:volatile关键字解析(写的非常好的一篇文章)

    原文出处: 海子 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volat ...

  6. 【NOI2002】银河英雄传说(并查集)

    [NOI2002]银河英雄传说 题面 题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军 ...

  7. 【POJ2387】Til the Cows Come Home (最短路)

    题面 Bessie is out in the field and wants to get back to the barn to get as much sleep as possible bef ...

  8. LightOJ1341 Aladdin and the Flying Carpet

    题意 给一对数字 a,b ,a是一个长方形的面积,问有多少种整数的边的组合可以组成面积为a的长方形,要求最短的边不得小于b 数据组数T<=4000, a,b<=10^12 Solution ...

  9. POI导出Excel的几种情况

    第一种:常见导出[已知表头(长度一定),已知表数据(具体一个对象的集合,并已知对象各个属性的类型)]第二种:不常见导出[已知表头(长度不定),已知表数据(没有具体对象,装在String类型的集合中)] ...

  10. Online Judge(OJ)搭建——4、具体实现

    代码编译.运行.保存: 本系统目前支持 Java.C++ 的编译.如有其他语言需要编译,扩展也很简单,因为这里使用了一个抽象类LanguageTest,处理好代码运行编译之前的文件保存,代码运行之中的 ...