1. 垃圾收集算法

 
    JVM的垃圾收集算法在不同的JVM实现中有所不同,且在平时工作中一般不会深入到收集算法,因此只对算法做较为简单的介绍。
 
    1.1 标记-清除算法
 
        这种算法是非常直观的,也是最为基础的收集算法(Mark-Sweep)算法,这种算法将回收分为两个阶段:首先标记所有需要回收的对象,然后在完成标记后统一回收掉被标记的对象。这种算法是如此的基础,以至于后面的算法都是基于该思路,并对其确定进行改进所得的。
 
        这种算法的缺点主要有两个:
 
        1. 效率较低,整个回收过程分为标记-回收两个阶段
 
        2. 内存碎片,标记清除之后存在较多内存碎片,可能导致需要连续的较大的内存空间时,没有满足需要的内存空间,从而不得不导致另外一次GC。
 
       
 
    1.2 复制算法
 
        为了解决效率问题,复制算法出现了,其将内存划分为容量相等的两块,每次只使用其中一块。当一块的内存用完了,就将活着的对象复制到另外的内存块上,然后把使用过的空间一次清理掉。这样只对一块内存空间进行回收,相当的高效。
 
        但这种算法的问题是将实际可用内存的大小缩小了一般,在内存价格还相当昂贵的今天,代价有些太高了。
 
       
 
    现在的商业虚拟机都使用此种算法来回收新生代,根据IBM研究表明,新生代中98%的对象是朝生夕死的,所以并不需要按照1:1来划分内存空间,而是将新生代划分为一块较大的Eden和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。
    回收时,将Eden和Survivor中存活的对象一次性复制到另外的Survivor空间,并清理掉Eden和Survivor空间。这样,可以减少浪费至10%,当survivor空间不够时,需要老年代进行分配担保(Handle Promotion,如果另一个Survivor没有足够空间,则存放到老年代)。
 
    1.3 标记 - 整理算法
 
        复制算法在存货对象较多时需要执行大量的复制操作,这对老年代来说是不合适的,因此有人就提出了标记-整理算法,过程与标记-清除算法一样,但后续步骤不是对可回收对象进行清理,而是让所有的对象都向一端移动,然后直接清理掉边界之外的内存。
 
       
 
        1.4 分代收集算法
 
            当前的商业虚拟机均使用分代收集算法,将对象按照存活周期分为几块,一般将Java堆分为新生代与老年代,从而可以根据不同年代的特点使用不同的收集算法。
 
            如新生代中存在大量死去的对象,只有少量存活,使用复制算法;老年代中因存活对象数量多,且没有额外空间,因此需要采用标记 - 清除或 标记 - 清理算法。
 
2. 垃圾收集器
 
    垃圾收集器是垃圾收集算法的具体实现,Java虚拟机对垃圾收集器如何实现并未做规定,因此不同厂商会有各自的垃圾收集器。如HotSpot虚拟机中的收集器如下所示,其中存在连线的收集器即可搭配使用。
 
    但现在没有最好的收集器,都需要根据具体环境来选择。
 
   
 
    2.1 Serial收集器
 
        串行收集器是最为基本的收集器,它是单线程的,而且在运行时,会停掉其他所有的工作线程(Stop the world),直到其收集结束。在实际应用中,用户很难忍受程序运行暂停。
 
        人们在努力的减少收集器的停顿时间,但没有办法完全消除,虽然Serial收集器有着种种缺点,但其简单而高效,对于Client型应用,其仍是新生代默认的收集器(桌面应用,内存小且停顿时间可忍受)。
 
    2.2 ParNew收集器
 
        ParNew收集器是Serial收集器的多线程版本,且加入了多个控制参数,并与Serial公用相当多的代码
 
        ParNew除了多线程之外,与其他Serial收集器相比并没有太多创新,但其却是许多运行在Server模式下虚拟机首选的新生代收集器,主要是由于它可以通CMS收集器相配合使用。
 
        在单CPU环境下,ParNew性能甚至不如Serial收集器(线程交互开销),但随着CPU数目上升,对于其收集效率还是很有提升的。
 
    2.3 Parallel Scavenge收集器
 
        新生代收集器,使用复制算法,其关注点在于控制吞吐量(Throughout,CPU用于运行用户代码与CPU总消耗时间的比值),主要适用于后台运算而不太关注用户交互的场合
 
    2.4 Serial Old收集器
 
        是Serial收集器的老年代版本,单线程,使用标记-清理算法
 
    2.5 Parallel Old收集器
 
        是Parallel Scavege收集器的老年代版本,使用多线程和”标记-整理“算法
 
    2.6 CMS(Concurrent Mark Sweep)收集器
 
        是一种以获取最短停顿时间为目标的收集器,常应用于重视服务响应速度的场景。其基于标记-清除算法。
 
        CMS收集器对CPU资源非常敏感,在并发阶段,虽然不会导致程序停顿,但由于占用了部分CPU资源,导致应用程序变慢,总的吞吐量变低。
        
        CMS无法处理浮动垃圾,可能出现”Concurrent Mode Failure“而导致另外一次Full GC的产生,这是由于在GC过程中,程序仍然运行,会不断产生垃圾所致
 
        CMS可能在收集结束后产生大量碎片,当碎片数量过多时,将会给大对象的分配带来困难
 
    2.7 G1收集器
 
        G1(Garbage First)收集器是最新的GC 收集器,其基于标记 - 整理算法,并且可以非常精确的控制停顿
 
        
    2.8 垃圾收集器总结
 
            没有完美的垃圾收集器,需要根据应用的实际情况进行选择和调优,有时候需要选择不同的收集器,有时需要选择收集器的参数
        
3. 内存分配与回收策略
 
    3.1 对象有优先在Eden区分配,如果没有足够空间,则会发起一次Minor GC -XX:SurvivorRatio=8决定一个新生代Eden与Survivor区比例为8:1
 
        其中新生代GC称为Minor GC,其发生非常频繁,速度也快
 
        其中老年代的GC称为Major GC,比Minor GC慢10倍以上
 
    3.2 大对象直接进入老年代
 
    3.3 长期存活的对象进入老年代(有相应的年龄计数器,活过一次GC则+1)
 
4. 总结
 
    内存回收与垃圾收集器在很多时候都影响系统性能、并发能力的主要因素,虚拟机有大量参数可供调节,只有根据实际需求、实现方式选择最优的收集方式才能获取最优的性能。没有固定收集器-算法的组合,也没有最优的调优方法,需要通过实践去逼近最高性能。
 
           

深入理解Java虚拟机 - 垃圾收集算法与垃圾收集器的更多相关文章

  1. 深入理解java虚拟机(四)垃圾收集算法及HotSpot实现

    垃圾收集算法 一般来说,垃圾收集算法分为四类: 标记-清除算法 最基础的算法便是标记-清除算法(Mark-Sweep).算法分为“标记”和“清除”两个阶段:首先标记处需要收集的对象,在标记完成之后,再 ...

  2. 深入理解java虚拟机(2)------垃圾收集器和内存分配策略

    GC可谓是java相较于C++语言,最大的不同点之一. 1.GC回收什么? 上一篇讲了内存的分布. 其中程序计数器栈,虚拟机栈,本地方法栈 3个区域随着线程而生,随着线程而死.这些栈的内存,可以理解为 ...

  3. 深入理解Java虚拟机 第三章 垃圾收集器 笔记

    1.1   垃圾收集器 垃圾收集器是内存回收的具体实现.以下讨论的收集器是基于JDK1.7Update14之后的HotSpot虚拟机.这个虚拟机包含的所有收集器有: 上图展示了7种作用于不同分代的收集 ...

  4. 《深入理解java虚拟机》读书笔记——垃圾收集与内存分配策略

    可回收判定两种算法 引用计数法(Reference Counting):引用为0时可回收. 可达性分析法(Reachability Analysis): 从GCRoots对象到这个对象不可达. GCR ...

  5. 《深入理解Java虚拟机》读书笔记-垃圾收集器与内存分配策略

    在堆里存放着java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前需要知道哪些对象还存活,哪些对象已经死去.那怎么样去判断对象是否存活呢? 一.判断对象是否存活算法 1.引用计数法 实现思路:给 ...

  6. 深入理解java虚拟机(五)垃圾收集器

    垃圾收集器 垃圾收集器是垃圾收集算法的具体实现.Java规范对垃圾收集器的实现没有做任何规定,因此不同的虚拟机提供的垃圾收集器可能有很大差异.HotSpot虚拟机1.7版本使用了多种收集器.如下图. ...

  7. 深入理解java虚拟机笔记Chapter3-垃圾收集器

    垃圾收集器 垃圾收集(Garbage Collection,GC),它的任务是解决以下 3 件问题: 哪些内存需要回收? 什么时候回收? 如何回收? 本节补充知识: ① s:Survivor区 新生代 ...

  8. 深入理解java虚拟机(九)类加载器以及双亲委派模型

    虚拟机把类加载阶段中“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到虚拟机外部去实现,以便让程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为“类加载器”. 类与类加载器 任 ...

  9. 《深入理解Java虚拟机》笔记02 -- 垃圾收集算法

    1. 标记 - 清除算法 先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象.它是最基础的收集算法.其他收集算法都是根据其思路,改进其不足之处. 缺点:1) 标记和清除两个阶段的效率都不 ...

  10. 《深入理解Java虚拟机》笔记03 -- 垃圾收集器

    收集器可以大致分为:单线程收集器, 并发收集器和并行收集器. 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态. 并发(Concurrent):指用户线程与垃圾收集 ...

随机推荐

  1. web一次请求的流程

    1.客户端(浏览器输入网址)请求 2.发送http协议到web服务器(nginx),检测请求类别,如果时纯静态页面,则返响应返回给客户端. 3.如果有动态脚本(php语法)启动fastcgi进程,用解 ...

  2. (转载)sql语句解决分页问题

    <来源网址:http://www.delphifans.com/infoview/Article_353.html>sql语句解决分页问题日期:2005年1月17日 作者:treemon2 ...

  3. The architecture of LTE network.

    3GPP定义的LTE网络架构结构变得扁平化,无线RNC/BSC 消失,只有eNodeB.控制面使用MME进行处理,用户面使用SGW和PGW进行处理.相比GSM和UMTS,在逻辑接口上定义了S1/X2逻 ...

  4. ENVI栅格文件增强后将LUT保存完输出img图像进行分类

    ENVI栅格文件储存 图像原始的DN(Digital Number)值记录图像的光谱信息,不能轻易更改。在窗口中显示的一般是经过拉伸等增强处理的LUT上的灰度值,在保存文件时,就有不同的方式。 1.  ...

  5. 【BZOJ 1070】[SCOI2007]修车

    Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使 ...

  6. NOSQL Mongo入门学习笔记 - 数据的基本插入(二)

    成功运行起来mongo之后,进入了命令行模式,mongo默认会选择test数据库 1. 使用db命令打印出来当前选定的数据库: > db test 2. 使用show dbs 命令可以打印出数据 ...

  7. java程序练习:数组中随机10个数中的最大值

    //定义输入:其实是一个可以保存10个整数的数组 //使用循环遍历,生成10个随机数,放入每个元素中//打桩,数组中的内容 //定义输出变量 //将数组中第一个元素取出,保存在max中,当靶子 //遍 ...

  8. 1042: [HAOI2008]硬币购物 - BZOJ

    Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法.Input 第一行 ...

  9. 2038: [2009国家集训队]小Z的袜子(hose) - BZOJ

    Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只 ...

  10. Mapped Statements collection does not contain value for

    这是由pojo的映射文件的命名空间引起的错误. 按照以下格式即可:命名空间中一定要含有mapper.xxMapper这样的格式,否则出现以上错误. <?xml version="1.0 ...