Java垃圾收集算法

 由于垃圾收集算法的实现涉及大量的程序细节,而且每个平台的虚拟机操作内存的方法又各不相同,因此博客中不过多的讨论算法的实现,只是介绍几种算法的思想以及发展。

  相关阅读:

  1、深入理解java虚拟机之java内存区域

  2、深入理解java虚拟机之对象真的死了吗

  1、标记-清除算法

  标记清除算法分为“标记”和“清除”两个阶段,首先先标记出那些对象需要被回收,在标记完成后会对这些被标记了的对象进行回收;如下图:

  这种算法的优点在于不需要对对象进行移动操作,仅对不存活的对象进行操作,所以在对象存活率较高的情况下效率非常高,但是从上图模拟的结果来看对象被回收后,可用的内存并不是连续的,而是断断续续,造成大量的内存碎片。 存储对象时要求内存空间时连续的,所以虚拟机在给新的内存较大的对象分配空间时,有可能找不到足够大的连续的空闲的空间来存放,从而引发一次垃圾回收动作,实际上里面是有大量的空闲空间的,只是不连续而已。

  2、复制算法

  复制算法是将内存分为两块大小一样的区域,每次是使用其中的一块。当这块内存块用完了,就将这块内存中还存活的对象复制到另一块内存中,然后清空这块内存。这种算法在对象存活率较低的场景下效率很高,比如说新生代,只对整块内存区域的一半进行垃圾回收,在垃圾回收的过程也不会出现内存碎片的情况,不需要移动对象,只需要移动指针即可,实现简单,所以运行效率很高。运行效率是在建立在浪费空间的基础上的,这是典型的已空间换时间的方法,因为每次只能是使用北村的一半。算法示意图如下:

  

  现在商用的jvm中都采用了这种算法来回收新生代,因为新生代的对象基本上都是朝生夕死的,存活下来的对象约占10%左右,所以需要复制的对象比较少,采用这种算法效率比较高。hotspot版本的虚拟机将堆(heap)内存分为了新生代和老年代,其中新生代又分为内存较大的Eden区和两个较小的survivor区。当进行内存回收时,将eden区和survivor区的还存活的对象一次性地复制到另一个survivor空间上,最后将eden区和刚才使用过的survivor空间清理掉。hotspot虚拟机默认eden和survivor空间的大小比例为8:1,也就是每次新生代中可用内存空间为整个新生代空间的90%(80%+10%),只会浪费掉10%的空间。当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于10%的对象存活,当survivor空间不够用时,需要依赖于其他内存(这里指的是老年代)进行分配的担保。

  3、标记-整理算法

  复制算法在对象存活率较高的情况下就要进行较多的对象复制操作,效率将会变低。更关键的是,如果你不需要浪费50%的空间,就需要有额外的空间进行分配担保,用以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种办法。

  根据老年代的特点,有人提出了标记-整理的算法,标记过程仍然与标记-清楚算法一样,但后续步骤不是直接将可回收对象清理掉,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存,算法示意图如下:

  4、分代收集算法

  分代收集算法将heap区域划分为新生代和老年代,新生代的空间比老年代的空间要小。新生代又分为了Eden和两个survivor空间,它们的比例为8:1:1。对象被创建时,内存的分配是在新生代的Eden区发生的,大对象直接在老年代分配内存,IBM的研究表明,Eden区98%的对象都是很快消亡的。

  为了提高gc效率,分代收集算法中新生代和老年代的gc是分开的,新生代发生的gc动作叫做minor gc 或 young gc,老年代发生的叫做major gc 或 full gc。

  minor gc 的触发条件:当创建新对象时Eden区剩余空间小于对象的内存大小时发生minor gc;

  major gc 触发条件:

  1、显式调用System.gc()方法;

  2、老年代空间不足;

  3、方法区空间不足;

  4、从新生代进入老年代的空间大于老年代空闲空间;

  Eden区对象的特点是生命周期短,存活率低,因此Eden区使用了复制算法来回收对象,上面也提到复制算法的特点是在存活率较低的情况下效率会高很多,因为需要复制的对象少。与一般的复制算法不同的是,一般的复制算法每次只能使用一半的空间,另一半则浪费掉了,Eden区的回收算法也叫做"停止-复制"算法,当Eden区空间已满时,触发Minor GC,清理掉无用的对象,然后将存活的对象复制到survivor1区(此时survivor0有存活对象,survivor1为空的),清理完成后survivor0为空白空间,survivor1有存活对象,然后将survivor0和survivor1空间的角色对象,下次触发Minor gc时重复上述过程。如果survivor1区剩余空间小于复制对象所需空间时,将对象分配到老年代中。每发生一次Minor gc时,存活下来的对象的年龄则会加1,达到一定的年龄后(默认为15)该对象就会进入到老年代中。

  老年代的对象基本是经过多次Minor gc后存活下来的,因此他们都是比较稳定的,存活率高,如果还是用复制算法显然是行不通的。所以老年代使用“标记-整理”算法来回收对象的,从而提高老年代回收效率。

  总的来说,分代收集算法并不是一种具体的算法,而是根据每个年龄代的特点,多种算法结合使用来提高垃圾回收效率。

  参考资料:《深入理解Java虚拟机》

Java垃圾收集算法1的更多相关文章

  1. JAVA 垃圾收集算法,垃圾收集器与内存分配策略(内容全面,解析简单易懂)

    垃圾收集器需要解决的三个问题: 1)哪些内存需要回收 2)什么时候回收 3)如何回收 背景:程序计数器,虚拟机栈,本地方法栈3个区域随线程而生,随线程而灭,在这几个区域内不需要过多的考虑回收的问题,因 ...

  2. JVM笔记3:Java垃圾收集算法与垃圾收集器

    当前商业虚拟机的垃圾收集都采用"分代收集"算法,即根据对象生命周期的不同,将内存划分几块,一般为新生代和老年代,不同的代根据其特点使用最合适的垃圾收集算法 一,标记-清除算法: 该 ...

  3. Java垃圾收集算法

    算法名称 过程 优缺点 1. 标记-清除算法 (Mark-Sweep) 分为两个阶段: 1.首先标记出所有需要回收的对象: 2.在标记完成后统一回收所有被标记的对象. 缺点: 1.效率问题:标记和清除 ...

  4. Java垃圾收集算法介绍

    垃圾回收器GC(Garbage Collection) 一.引用计数算法(Reference Counting) 介绍:给对象添加一个引用计数器,每当一个地方引用它时,数据器加1:当引用失效时,计数器 ...

  5. 【Java】JVM(二)、Java垃圾收集算法

    一.标记-清除算法 算法主要分为两个步骤 1. 标记: 遍历所有的 GC Roots, 然后标记所有可达对象为存活对象 2. 清除: 遍历堆中所有对象,然后将没有标记的对象清除. 存在不足: 1. 效 ...

  6. jvm系列(三):java GC算法 垃圾收集器

    GC算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计 ...

  7. 深入理解Java虚拟机 - 垃圾收集算法与垃圾收集器

    1. 垃圾收集算法       JVM的垃圾收集算法在不同的JVM实现中有所不同,且在平时工作中一般不会深入到收集算法,因此只对算法做较为简单的介绍.       1.1 标记-清除算法        ...

  8. Java面试常考------------------------垃圾收集算法

    对于Java系学生而言,Java虚拟机中的垃圾收集算法是一个很重要的面试考点. 常用的垃圾收集算法主要可划分为以下三类: 1. 标记-清除算法 标记清除算法是一种比较简单的方法,直接标记内存中待回收的 ...

  9. Java GC算法 垃圾收集器

    GC算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被称为"GC",它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. ...

随机推荐

  1. Mac OS 系统开发环境的一些坑

    最近换 Mac OS 系统开发,运行项目时遇到各种报错,记录下: 1.拉取项目后,需要安装依赖 npm install ,提示需要安装 xcode,报错如下. 从官网下载 xcode 时提示要更新最新 ...

  2. blur([[data],fn]) 当元素失去焦点时触发 blur 事件。

    blur([[data],fn]) 概述 当元素失去焦点时触发 blur 事件.大理石平台生产厂 这个函数会调用执行绑定到blur事件的所有函数,包括浏览器的默认行为.可以通过返回false来防止触发 ...

  3. [Luogu] 列队

    https://www.luogu.org/problemnew/show/P3960 如果 x = 1,相当于维护一条链,每次取出第 k 个数放在序列末尾假设有 n + m + q 个位置,每个位置 ...

  4. Appium基础教程

    目录 Appium教程 Appium简介 App自动化测试工具对比 Appium实现原理 环境搭建 Andorid介绍 基本架构 常见布局/视图 基本控件 控件常见属性 Adb介绍 Adb常用命令 A ...

  5. 理解TCP三次握手和四次挥手

    TCP相关知识 TCP是面向连接的传输层协议,它提供可靠交付的.全双工的.面向字节流的点对点服务.HTTP协议便是基于TCP协议实现的.(虽然作为应用层协议,HTTP协议并没有明确要求必须使用TCP协 ...

  6. codeforces#1165 F2. Microtransactions (hard version) (二分+贪心)

    题目链接: https://codeforces.com/contest/1165/problem/F2 题意: 需要买$n$种物品,每种物品$k_i$个,每个物品需要两个硬币 每天获得一个硬币 有$ ...

  7. Java关键字volatile的实现原理(四)

    简述 volatile 是轻量级的synchronized,在多线程开发中保证了共享变量的可见性.可见性就是当一个线程修改一个共享变量时,另一个线程可以读到修改的值.如果volatile变量使用恰当, ...

  8. Codeforces Round #371 (Div. 2)

    之前做过E题,是一个DP. A题,水题,两线段求交集. B题,set一下判断即可. C题,水题.但是我写麻烦了,直接转化成二进制再做,比用字符串relize()以后再map要好写得多. D题,交互题, ...

  9. Python中调用shell

    1 简单调用shell命令 os.system(command) 在一个子shell中运行command命令, 并返回command命令执行完毕后的退出状态. 这实际上是使用C标准库函数system( ...

  10. No suitable constructor was found in NUnit Parameterised tests

    No suitable constructor was found in NUnit Parameterised tests Fairly obvious, but can also happen i ...