一、引入

上篇博客《JVM——简介》中主要介绍了JVM的内存模型,思考一下:

为什么要划分堆、栈、方法区等?

为什么把不同种类的数据信息分别存放?

答案可以分为很多很多条,这里就说一个方面,如果我们是如何区分数据的种类的,那就是作用域。比如:堆、方法区是线程共享的,而栈是私有的。

那么管理又包括哪些方面呢?包括创建、存储、回收?这篇博客就来谈谈垃圾回收(Garbage Collection)。

小编建议各位读者把自己当成GC,那个以回收垃圾为工作的人,这么说貌似有点……

二、算法

问自己三个问题:

what——回收什么

how——怎么回收

when——什么时候回收

1、What

作为GC,我们要回收些什么?对象实例、变量、类型信息……你怎么知道哪些要回收哪些不需要回收呢,是不是还应用该对象实例,这个对象死了吗?

判断一个对象死了吗,听着很简单,做起来就不是那么一回事了。

1)计数器

给每个对象实例绑一个计数器,如果有人引用他,就加1,不再引用之后,就减1。那么当值为0时,应该就是不被使用的了。

实现简单,效率也高,但解决不了循环引用的问题。即A引用B,B引用A,按照这种思路,他们就要永久的绑在一起了。

2)引用链

假定有一个Root节点,作为起始点,向下搜索,当某个对象没有在这条链上时,即他怎么都走不到Root的时候,我们就说他是不再使用的,可以被回收。

懒得画了,从网上找了个图。

2、How

1)标记-清除

两个阶段:先标记,后统一回收。

这个办法很简单很基础,但真的是不怎么看好。时间上,两个过程效率都不高;空间上,会产生大量的空闲碎片,不利于再次使用。

那怎么办?看后面的方法对他进行改进。

2)复制

主要解决效率问题。

先将内存划分相同大小的两块区域,只使用其中一块。当这一块内存用完了,将对象拷贝到没使用的那块内存区域上,然后进行清理。

不足之处很明显了,内存很宝贵的呀!!!这简直是复制算法的致命伤,

提出这个观点的估计是个没受过穷的富家公子啊。

3)标记-整理

主要解决了内存碎片问题。

他的过程前半部分跟标记-清除一样,就在清理之后,让还活着对象移动到一端,把碎片问题解决了。

当然,效率肯定没有标记-清除好了,不过平衡了一下,这个算法还不错。

3、When

GC不能精准的控制回收的具体时间,但分代收集可以控制到一个回收的频率。

言归正传,文章最开始说到了堆和栈中存放的数据作用域(生命周期)是不同的,那么他们的回收频率肯定不一样。其实实际上要更复杂一点,堆内部的对象实例存活的时间也各有不同,如果每次回收都扫描一遍,那效率是十分低下的。基于这一点,引出著名的分代收集的算法。

分代收集

大致分为三个年代:新生代、老年代和永久代。新生代中又分出两个区域:S0(Survivor0)、S1(Survivor1)。个别名字可能翻译的不同,理解就好。

新生代

Eden:伊甸园的意思,这里一般存储新创建的对象。这些对象有两种结局,要么被收集清理掉,要么移到下一个Survivor Space中。

Survivor:幸存者,大致是说他们已经死里逃生一次了。

老年代

Old Space:在新生代中对象达到一定比例后,就会将多余的对象移入老年代。

永久代

前面两种都是存放在堆中的,因此,又可以把老年代看作是新生代的“备用仓库”。而永久代是在方法区中的,回收频率是最慢的。

各个年代有各个年代的特点,他们也就可以选择适合自己的算法来进行回收。新生代每次回收的数量都很大,可以使用复制算法。老年代对象存活的时间长,空间也不大,就只能使用“标记-清理”或者“标记-整理”了。

分代收集算法其实还是利用How中的几个基本算法,只是划分区域(年代),更科学的使用收集算法。

三、收集器

前面解决了垃圾回收的what、how、when的问题,那么就要开始实打实的干活了!谁去干?怎么干呢?

收集器就是帮助我们去解决这个问题的,每个特点也是不一样的,在单独介绍之前,我们先来分分类。

标准 收集器
年代 新生代、老年代
工作模式 串行、并行、并发
碎片处理 压缩、非压缩
…… ……

没有最好的收集器,也没有万能的收集器,只有挑选更适合的才是科学的。

1)Serial

adj.

1. 连续的;一连串的;一系列的。

2.按期出版的;(小说等)连载的;连续刊行的;连续广播的。

3.分期偿付的。

4.【计算机】中行的;串联的。

特点:

简单;

单线程;

新生代。

2)ParNew

Serial的多线程版本;

新生代;

3)Parallel Scavenge

Parallel

adj.

1.平行的;并行的 (to; with); 【电学】并联的。

2.同一方向的,同一目的的。

3.相同的,同样的,相似的,对应的。

新生代;

并行;

重视吞吐量(这个后面说)。

4)CMS

Concurrent Low Pause Collector 并发低停顿收集器

重视停顿时间,响应速度快,带给用户良好体验。

过程比较复杂,篇幅有限,不再介绍了。

5)G1

并发;

分代收集;

标记-整理;

降低停顿时间。

分类

上面只是介绍了几个比较典型的收集器,从年代的角度来看一下:

注意:横线以上是新生代,以下是老年代。收集器之间的连线表示他们之间可以配合使用。

小结:

新生代基本采用复制算法,老年代采用标记整理算法。

两种算法都解决了碎片问题,由于新生代的空间较大,可以采用复制,更高效些。

从工作方式上来看:

  1. 串行

    垃圾回收时,”Stop the World”暂停所有线程。如:Serial/Serial Old

  2. 并行

    多个线程可以同时执行,适合多CPU。如:Parallel Scavenge

  3. 并发

    部分收集工作可以和用户线程交替执行。如:CMS

串行只适合小数据量,这是CPU占用率高,效率快。

怎样挑选适合自己的收集器呢?

可以从这几个方面考虑:

Client模式:优先考虑用户体验,响应要快,停顿时间不能太长。

Server模式:吞吐量优先,更高效率的利用CPU,尽快完成任务,适合后台运算。吞吐量=运行代码时间/(运行代码+GC)。

JVM(2)——GC算法和收集器的更多相关文章

  1. JVM 的GC算法和垃圾收集器

    1.标记清除算法 黑色部分代表可回收对象,灰色部分代表存活对象,绿色部分代表未使用的.最基础的收集算法就是标记清除算法如同他名字一样,算法分为"标记"和"清除" ...

  2. jvm特性(3)( 收集算法和收集器的概念)

    java内存模型和线程规范 JVM高级特性与实践(三):垃圾收集算法 与 垃圾收集器实现 大致知识点如下: 4种垃圾收集算法概念的学习 7种垃圾收集器特征的学习 一. 垃圾收集算法 1. 标记-清除算 ...

  3. 深入JVM系列(二)之GC机制、收集器与GC调优

    一.回想JVM内存分配 须要了解很多其它内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配 2.大对象直接进入老年代  3.长期存活的 ...

  4. 深入JVM系列(二)之GC机制、收集器与GC调优(转)

    一.回顾JVM内存分配   需要了解更多内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配2.大对象直接进入老年代 3.长期存活的对象 ...

  5. JVM(二)GC算法和垃圾收集器

    前言 垃圾收集器(Garbage Collection)通常被成为GC,诞生于1960年MIT的Lisp语言.上一篇介绍了Java运行时区域的各个部分,其中程序计数器.虚拟机栈.本地方法栈3个区域随线 ...

  6. JVM学习九:JVM之GC算法和种类

    我们前面说到了JVM的常用的配置参数,其中就涉及了GC相关的知识,趁热打铁,我们今天就学习下GC的算法有哪些,种类又有哪些,让我们进一步的认识GC这个神奇的东西,帮助我们解决了C 一直挺头疼的内存回收 ...

  7. JVM垃圾回收算法 及 垃圾收集器

    摘自<深入理解Java虚拟机> 一.什么是: GC算法是 方法论,那么垃圾收集器就是具体的 实现. 二.四种 垃圾回收算法 1.标记-清除算法:最基础的收集算法:不足有两点:1标记和清除两 ...

  8. JVM垃圾回收之CMS收集器

    从前文JVM垃圾回收几种常见算法和常见收集器我们知道,CMS是老年代垃圾收集器.CMS 收集器主要关注系统停顿时间.CMS 是 Concurrent Mark Sweep 的缩写,意为并发标记清除,从 ...

  9. (转)jvm具体gc算法介绍标记整理--标记清除算法

    转自:https://www.cnblogs.com/ityouknow/p/5614961.html GC算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被称为“GC”, ...

随机推荐

  1. js面向对象轮播图写法

    ;;}         ,,,;}         ];     ].].;     ){             ;             ;         }) } Banner.protot ...

  2. SpringMVC中session使用&&拦截器&&乱码处理&&异常处理

    ### 1. 使用Session 通常,会在Session中存放: 1. 客户端(用户)的身份标识,通常是用户的id:2. 使用频率非常高的数据,例如显示在页面中的用户名.头像等:3. 其它的不便于使 ...

  3. I/O流、文件操作

    1)操作文件 Path和Files是在JavaSE7中新添加进来的类,它们封装了在用户机器上处理文件系统所需的所有功能.Path表示的一个目录名序列,其后还可以跟着一个文件名.路径中的第一个参数可以是 ...

  4. PHP命令行(CLI模式)

    CLI模式 CLI模式其实就是命令行运行模式,英文全称Command-Line Interface(命令行接口) $ php -h Usage: php [options] [-f] <file ...

  5. 微信小程序 嵌套循环

    前言 入门教程之列表渲染多层嵌套循环,目前官方的文档里,主要是一维数组列表渲染的案例,还是比较简单单一,给刚入门的童鞋还是无从入手的感觉. <view wx:for="{{items} ...

  6. 学习新框架laravel 5.6 (第二天)-DB,控制器及模型使用

    DB类使用,控制器使用及模型使用 链接数据库: /config/database.php /.env DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=330 ...

  7. spark-day1

    #!/usr/bin/python # -*- coding: utf_8 -*- from pyspark import SparkConf, SparkContext import os, tim ...

  8. 017---Django的中间件解决跨域

    跨域 跨域是什么? 浏览器从一个域名的网页去请求另一个域名的资源的时候,如果不同源.请求的响应结果就会被浏览器的同源策略所拦截 同源策略是什么? 同源:协议 + 域名 + 端口 特点:阻止ajax请求 ...

  9. node 分层开发

    app.js var express = require('express');var app = express();app.use('/',require('./control'));app.us ...

  10. Python3乘法口诀表(由上至下+由下至上)

    一.所用知识点: 1.变量的使用. 2.循环语句的使用,这里用到的是双while循环.当然,使用其他的循环去做也是可以的.我认为,对于刚刚接触编程的人来说,使用双while循环比较容易理解. 3.使用 ...