继续接着上一次【https://www.cnblogs.com/webor2006/p/10729649.html】的来学习,上次在结尾处提到了JVM常见的GC算法,如下:

接下来则逐一的对其进行学习,不过还是纯理论,比较枯燥但是必须得过一遍。

标记-清除算法(Mark-Sweep):

  • 算法分为“标记”和“清除”两个阶段,首先标记出所有需要回收的对象,然后回收所有需要回收的对象。
  • 缺点:
    a、效率问题:标记和清理两个过程效率都不高。
    b、空间问题:标记清理之后会产生大量不连续的内存碎片,空间碎片太多可能会导致后续使用中无法找到足够的连续内存而提前触发另一次的垃圾搜集动作。

下面用图表说明一下整个算法的过程,首先初始内存为:

可以看到从栈中有两个引用指向了堆,而堆中的对象存有互相引用的情况,其中左侧的栈可以称为Root GC,它可达的对象为A和B,如下:

其中标绿的是不能被GC回收的,接着继续:

最终内存的可达情况为:

其中标红的则是不能被Root GC所能引用的,也就是应该是被回收掉的,所以被回收之后整个图就变成了:

所以从上图的整个过程也能看到:

  • 效率不高,需要扫描所有对象,堆越大,GC越慢。
  • 存在内存碎片问题。GC次数越多,碎片越严重。

复制搜集算法(Copying):

  • 将可用内存分为两块,每次只使用其中的一块,当半区内存用完了,仅将不存活的对象复制到另外一块上面,然后就把原来整块内存空间一次性清理掉。
  • 这样使得每次内存回收都是对整个半区的回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存就可以了,实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一半,代价高昂。
  • 现在的商业虚拟机中都是用了这一种收集算法来回收新生代【啥叫新生代呢?通常情况下刚new出来的对象都会位于新生代当中,当新生代经历了几轮垃圾回收之后,尚未被回收的对象,这时JVM就会认为这些对象的存活时间比较长,则会将它们晋升到老年代中】。
  • 将内存分为一块较大的eden空间和2块较少的survivor【幸存者】空间,每次使用eden和其中一块survivor,当回收时将eden和survivor还存活的对象一次性拷贝到另外一块survivor空间上,然后清理掉eden和用过的survivor。
  • Oracle Hotspot虚拟机默认eden和survivor的大小比例是8:1,也就是每次只有1%的内存是“浪费”的。
  • 复制收集算法在对象存活率高的时候,效率有所下降。
  • 如果不想浪费50%的空间,就需要有额外的空间进行分配担保用于应付半区内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。

下面则来用图来理解一下它的流程:

其中From-Space则是真正对象存放的空间,而To-Space则是垃圾回收之后接收被复制对象的空间,如上图,由于Stack引用了A和C,则会将A和C拷贝到To-Space空间中,而由于C引用了H、K,所以H也会进到To-Space中,如下:

另外由于H又引用了L,所以L也会进来,如下:

而又引用了B、E、I,则都会进来:

其中D、G是没有被Stack所引用,照理只回收这俩就成了,但是!!此时则会将From-Space全部给清空,如下:

下面再对其进行一些特点描述:

  • 只需要扫描存活的对象,效率更高。
  • 不会产生碎片。
  • 需要浪费额外的内存作为复制区。
  • 复制算法非常适合生命周期比较短的对象,因为每次GC总能回收大部分的对象,复制的开销比较小。
  • 根据IBM的专门研究,98%的Java对象只会存活1个GC周期,对这些对象很适合用复制算法。而且不用1:1的划分工作区和复制区的空间。

标记-整理算法(Mark-Compact):

它的标记过程跟上面的复制搜索算法是一样的,但后续步骤不是进行直接清理,而是令所有存活的对象一端移动,然后直接清理掉这端边界以外的内存。
如图:

可以看到下面就是进行了回收整理的空间,它的特点是:

  • 没有内存碎片
  • 比Mark-Sweep(标记清除算法)耗费更多的时间进行compact(压缩整理)

分代收集(Generational Collecting)算法

  • 当前商业虚拟机的垃圾收集都是采用“分代收集”(Generational Collecting)算法,根据对象不同的存活周期将内存划分为几块。
  • 一般是把Java堆分作新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法,譬如新生代每次GC都有大批对象死去,只有少量存活,那就选用复制算法只需要付出少量对象的复制成本就可以完成收集。
  • 综合前面几种GC算法的优缺点,针对不同生命周期的对象采用不同的GC算法,比如:

    New代表新生代,如之前所说它里面的垃圾回收算法可以采用复制算法,而对于Old老年代的内存则可以通过标记清除算法或者标记整理算法。

  • Hotspot JVM6中共划分为三个代:年轻代(Young Generation)、老年代(Old Generation)、和永久代(Permanent Generation,注意这个是对于JDK8之前而言的,在JDK8之后此代是没有了)。如下图:

    在最开始时,对象是处于年轻代中,如下:

    然后对象是存在其中的Eden Space和From Space中,这俩的比例是可以调整的,其整个默认比例是8:1:1,而当进行垃圾回收时,则会将Eden Space和From Space留下来的对象都转到To Space上去,此时Eden Space和To Space又可以搭配工作,此时图中的From Space就变为了To Space,而图中的To Space又变成了From Space。而经过了几次回收之后,年轻代的对象就会进入到老年代,如下:

    而最终还有一个永久代,它是针对JDK8之前而存在的,如下:

    下面再具体来看一下各代的概念:

  • 年轻代(Young Generation)
    1、新生成的对象都放在新生代。年轻代用复制算法进行GC(理论上,年轻代对象的生命周期非常短,所以适合复制算法)。
    2、年轻代分三个区。一个Eden区,两个Survivor区(可以通过参数设置Survivor个数)。对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到一个Survivor区,当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当第二个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制到老年代。2个Survivor是完全对称,轮流替换。
    3、Eden和2个Survivor的缺省比例是8:1:1,也就是10%的空间会被浪费。可以根据GC log的信息调整大小的比例。
  • 老年代(Old Generation)
    1、存放了经过一次或多次GC还存活的对象。
    2、一般采用Mark-Sweep或者Mark-Compact算法进行GC。
    3、有多种垃圾收集器可以选择。每种垃圾收集器可以看作一个GC算法的具体实现。可以根据具体应用的需求选用合适的垃圾收集器(追求吞吐量?追求最短的响应时间?)。
  • 永久代【注意:从JDK8开始已经用元空间来替代它了】
    1、并不属于堆(Heap)。但是GC也会涉及到这个区域。
    2、存放了每个Class的结构信息,包括常量池、字段描述、方法描述。与垃圾收集要收集的Java对象关系不大。

JVM垃圾回收算法分析与演示【纯理论】的更多相关文章

  1. JVM垃圾回收重要理论剖析【纯理论】

    JVM学习到这里,终于到学习最兴奋的地方了---垃圾回收,在学习它之前还得对JVM垃圾回收相关理论知识进行了解,然后再通过实践来加深对理论的理解,下面直接开始了解相关的理论: JVM运行时内存数据区域 ...

  2. JVM垃圾回收机制总结:调优方法

    转载: JVM垃圾回收机制总结:调优方法 JVM 优化经验总结 JVM 垃圾回收器工作原理及使用实例介绍

  3. JVM内存管理和JVM垃圾回收机制

    JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...

  4. JDK分析工具&JVM垃圾回收(转)

    转自:http://blog.163.com/itjin45@126/blog/static/10510751320144201519454/ 官方手册:http://docs.oracle.com/ ...

  5. 老李分享:jvm垃圾回收

    老李分享:jvm垃圾回收   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478 ...

  6. jvm - 垃圾回收

    jvm - 垃圾回收 注意 : 本系列文章为学习系列,部分内容会取自相关书籍或者网络资源,在文章中间和末尾处会有标注 垃圾回收的意义 它使得java程序员不再时时刻刻的关注内存管理方面的工作. 垃圾回 ...

  7. JVM垃圾回收机制概述

    JVM垃圾回收机制概述 1.定义 是指JVM用于释放那些不再使用的对象所占用的内存. 2.方式 2.1引用计数(早期) 当引用程序创建引用以及引用超出范围时,JVM必须适当增减引用数.当某个对象的引用 ...

  8. Java虚拟机学习笔记——JVM垃圾回收机制

    Java虚拟机学习笔记——JVM垃圾回收机制 Java垃圾回收基于虚拟机的自动内存管理机制,我们不需要为每一个对象进行释放内存,不容易发生内存泄漏和内存溢出问题. 但是自动内存管理机制不是万能药,我们 ...

  9. JVM基础系列第8讲:JVM 垃圾回收机制

    在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...

随机推荐

  1. 基于Spring Boot架构的前后端完全分离项目API路径问题

    最近的一个项目采用前后端完全分离的架构,前端组件:vue + vue-router + vuex + element-ui + axios,后端组件:Spring Boot + MyBatis.之所以 ...

  2. WeQuant教程—1.5 实盘运行须知

    为了保证实盘交易程序能够正常稳定地运行,同时保护您在使用时账户资金的安全,我们设计了一些规则和机制.了解这些机制有助于您更快上手实盘交易. 启动前检查机制 在实盘交易程序启动前,系统会执行一次检查,出 ...

  3. Xcode7.2真机测试问题"The account 'appleID ' has no team with ID ‘’

     在Xcode7(测试版)提出免费真机测试的时候,我立刻在网上搜寻测试步骤,很简单,按照步骤走就可以. 但在7.2以后,突然我的iPhone不能真调了!提示"The account 'app ...

  4. 阿里云k8s事件监控

    事件监控是Kubernetes中的另一种监控方式,可以弥补资源监控在实时性.准确性和场景上的缺欠.Kubernetes的架构设计是基于状态机的,不同的状态之间进行转换则会生成相应的事件,正常的状态之间 ...

  5. readiness与liveness

    一.liveness(存活探针)方式 HTTP GET:对指定的端口和路径执行http get请求,返回非错误代码即代表正常 TCP socket:对指定端口建立TCP链接,链接通过则代表正常 Exe ...

  6. odoo self.ensure_one()

    源码: def ensure_one(self): """ Verifies that the current recorset holds a single recor ...

  7. java内存模型,内存区域

    Java虚拟机内存区域总结:Java虚拟机相当于一个抽象的计算机操作系统, 其管理的内从区域大体上可以分为栈和堆,就像c或c++中对内存的分类一样, 但这样的分类对于Java虚拟机来说太过粗浅, 实际 ...

  8. es内存不够

    8核32G 3台 ELS机器,当时只给es配置了8G内存,es的总体数据量大小将近30G(查看GET /_cat/shards?v)

  9. 域名解析中的cname解析和显性URL跳转和隐性URL跳转三者有什么区别

    通俗的来讲,cname解析还是属于dns解析,只是把某个域名解析到另外一个域名对应的某个IP的空间中,所以还需要在服务器端(比如nginx)做域名解析(比如把baidu.com做一个cname解析到i ...

  10. Spring 学习指南 第三章 bean的配置 (未完结)

    第三章 bean 的配置 ​ 在本章中,我们将介绍以下内容: bean 定义的继承: 如何解决 bean 类的构造函数的参数: 如何配置原始类型 (如 int .float 等) .集合类型(如 ja ...