说到Java,一定绕不开GC,尽管不是Java首创的,但Java一定是使用GC的代表。GC就是垃圾回收,更直接点说就是内存回收。是对内存进行整理,从而使内存的使用尽可能大的被复用。 一直想好好写一篇关于GC的文章,可是却发现要写的东西太大了,不是一篇博客能简单的介绍完的。所以打算拆分成若干篇博客,一点点的总结下来。 本篇主要介绍的是GC中的常用算法。这些算法被广泛的应用于各个内存管理语言的虚拟机中,或者是各大常用的操作系统中。 说到GC,也就是垃圾回收,那么需要做的事有两件:

第一件是查找到哪些内存中的对象是已经废弃掉的。
第二件事是如何清理掉这些已经废弃掉的数据。
本文先来说说后者,如何清除掉这些内存中的废弃数据。

1、标记清除算法Mark-Sweep

这种算法是最简单最直接的算法,也是其它算法的一些最初思路。标记清除算法其实就是对内存中的对象依次的进行判断,如果对象需要回收那么就打一个标记,如果对象仍然需要使用,那么就保留下来。这样经过一次迭代之后,所有的对象都会被筛选判(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )断一次。紧接着会对内存中已经标记的对象依次进行清除。 这个算法比较简单粗暴,实现起来比较简单。但是会留下两个比较麻烦的问题: (1)标记和清除需要两遍循环内存中的对象,标记本身也是一个比较麻烦的工作,因此这种算法的效率不是特别的高。 (2)对于分配的内存来说,往往是连续的比较好,因为这样有利于分配大数据的对象。倘若当前内存中都是小段的内存碎片,会知道需要分配大段内存时,没有可以放置的位置,而触发内存回收。也就是空间不足而导致频繁GC和性能下降。

2、复制算法Copying

我在使用数据库的过程中,曾经遇到这样一个问题,表中的数据量相对来说比较大,大概30万行,需要使用多个苛刻的条件删除其中的大部分数据(因此无法使用索引),而只保留其中的较少数据。常规的delete语法使用起来是超时的。于是我查看维护人员的sql,发现一个很有意思的逻辑。首先查出数据库表中需要保留的数据,放到一张临时表中。然后彻底删除掉原有的数据表。然后把这张临时创建表的表名,改为当初的表名。这是一种典型的空间换取时间的方法。而复制算法就是这样一个思路。 复制算法中,会将内存划分为两块相等大小的内存区域A/B,然后生成的数据会存放在A区,当A区剩余空间不足以存放下一个新创建的对象时,系统就会将A区中的有效对象全部复制到B区中,而且是连续存放的。然后直接清空A区中的所有对象。 由于编程语言中的对象,大部分在创建后很快就(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )会被回收掉,所以我们需要复制的对象其实并不多。 Java中的实现是这样的: Java中将Eden和Survivor区同时作为复制算法的使用区域。Survivor又分为From区和To区。这块内容可以参考我的另外一篇博客有详细的介绍:。每次GC的时候都会将Eden和Survivor的From区中的有效对象进行标记,一同复制到Survivor的To区。然后彻底清除原来的Eden区和From区的内存对象。与此同时To区就是下一次回收的From区。

复制算法的缺点: 算法使用了空间换取时间的思路,因此需要一块空白的区域作为内存对象要粘贴的区域。这无疑会造成一种浪费。尤其是内存较小时。 算法每次清除无效对象时,都要进行一次复制粘贴的对象转移,因此对使用场景是有限制的。只有在有效对象占据总回收内存是非常小的时候,这种算法的性价比才会达到最高。否则大量的复制动作所浪费的时间可能要远远大于空间换取时间得到的收益。因此这种算法在Jvm中,也只被用来作为初级的对象回收。因为这时的有效对象比例最低,算法的性价比是最高的。

3、 标记整理算法 Mark-Compact

复制算法需要一块额外的内存空间,用于存放幸存的内存对象。这无疑造成了内存的浪费。我们还可以在原有的标记清除算法的基础上,提出了优化方案。也就是标记到的可用对象整体向一侧移动,然后直接清除掉可用对象边界意外的内存。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )这样既解决了内存碎片的问题。又不需要原有的空间换时间的硬件浪费。由于老年代中的幸存对象较多,而且对象内存占用较大。这就使得一旦出现内存回收,需要被回收的对象并不多,碎片也就相对的比较少。所以不需要太多的复制和移动步骤。因此这种方法常常被应用到老年代中。 标记整理算法的缺点: 标记整理算法由于需要不断的移动对象到另外一侧,而这种不断的移动其实是非常不适合杂而多的小内存对象的。因此在使用场景上,就注定限制了标记整理算法的使用不太适合频繁创建和回收对象的内存中。

4、分代收集算法  Generational Collection

这种算法就是将内存以代的形式划分,然后针对情况分别使用性价比最高的算法进行处理。在Java中,一般将堆分为老年代和新生代。新创建的对象往往被放置在新生代中。而经过不断的回收,逐渐存活下来的对象被安置到了老年代中。越新的对象越可能被回收,越老的对象反而会存活的越久。因此针对这两种场景,新生代和老年代也会分别采用前文所述的两种算法进行清理。

ps:话说现在写篇博客越来越难了,今天以为画个图就可以发布了,结果画图画了一个小时。哎

JVM GC-----垃圾回收算法的更多相关文章

  1. JVM(九):垃圾回收算法

    JVM(九):垃圾回收算法 在本文中,我们将从概念模型的角度探讨 JVM 是如何回收对象,包括 JVM 是如何判断一个对象已经死亡,什么时候在哪里进行了垃圾回收,垃圾回收有几种核心算法,每个算法优劣是 ...

  2. JVM G1垃圾回收算法简要介绍

    JVM G1垃圾回收算法简要介绍 G1的特点 能够像CMS垃圾回收算法一样并发操作应用线程(潜台词:多核) 无需太长时间即可压缩空闲内存空间(潜台词:不会引起太多的GC停顿时间) 尽可能地让GC时长可 ...

  3. jvm详情——3、JVM基本垃圾回收算法回收策略

    JVM基本垃圾回收算法回收策略 引用计数(Reference Counting):比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回收时,只用收集计数为0的 ...

  4. JVM常见垃圾回收算法

    jdk1.7.0_79 众所周知,Java是一门不用程序员手动管理内存的语言,全靠JVM自动管理内存,既然是自动管理,那必然有一个垃圾内存的回收机制或者回收算法.本文将介绍几种常见的垃圾回收(下文简称 ...

  5. jvm的垃圾回收算法

    一.对象存活判断判断对象是否存活一般有两种方式:1.引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收.此方法简单,无法解决对象相互循环引用的问题.2 ...

  6. Java GC 垃圾回收算法 内存分配

    垃圾回收(Garbage Collection, GC)是Java不同于c与c++的重要特性之一. 他帮助Java自动清空堆中不再使用的对象. 由于不需要手动释放内存,程序员在编程中也可以减少犯错的机 ...

  7. 深入理解JVM一垃圾回收算法

    我们都知道java语言与C语言最大的区别就是内存自动回收,那么JVM是怎么控制内存回收的,这篇文章将介绍JVM垃圾回收的几种算法,从而了解内存回收的基本原理. 一.stop the world 在介绍 ...

  8. jvm学习-垃圾回收算法(三)

     垃圾回收算法  引用计数法 比较古老的一种垃圾回收算法.在java的GC并没有采用 增加一个引用 引用+1 减少一个引用引用减一 每次清除引用为0的的对象 缺点:不能回收循环引用的垃圾对象 标记清除 ...

  9. Java学习之二(线程(了解) JVM GC 垃圾回收)

    线程与进程(了解)→JVM→字节码→GC 一.程序 = 算法 + 数据结构(大佬) 二.程序 = 框架 + 业务逻辑(现实) 1.线程与进程.同步与异步 1.1进程是什么? 进程就是操作系统控制的基本 ...

  10. 深入探究JVM之垃圾回收算法实现细节

    @ 目录 前言 垃圾回收算法实现细节 根节点枚举 安全点 安全区域 记忆集和卡表 写屏障 并发的可达性分析 低延迟GC Shenandoah ZGC 总结 前言 本篇紧接上文,主要讲解垃圾回收算法的实 ...

随机推荐

  1. 【一天一道LeetCode】#54. Spiral Matrix

    一天一道LeetCode系列 (一)题目 Given a matrix of m x n elements (m rows, n columns), return all elements of th ...

  2. Cocos2D中的Framerate状态

    对于额外绘制调试物理引擎的支持,Cocos2D同样可以绘制概述计数器,尤其是帧速率(framerate)显示. 为了启用这些概述计数器标签,你只需添加如下一行代码,比如说在AppDelegate.m里 ...

  3. Android群英传笔记——第十章:Android性能优化

    Android群英传笔记--第十章:Android性能优化 随着Android应用增多,功能越来越复杂,布局也越来越丰富了,而这些也成为了阻碍一个应用流畅运行,因此,对复杂的功能进行性能优化是创造高质 ...

  4. Android万能的指示器

    说到 ViewPager 指示器,想必大家都不陌生,绝大部分应用中都有这个.使用频率非常之高.但系统对它的支持并不好,自带的 PagerTabStrip 和 PagerTitleStrip 太弱,很难 ...

  5. 一个操作cvs格式的c++类

    经常需要使用excel,或者把有的数据用excel打开,程序可以生成cvs格式的文件,这样就可以excel打开并处理了,于是找了一个处理cvs的c++类跟大家分享 代码出处找不到了: 代码如下: St ...

  6. 【Java编程】Java在dos窗口编译与执行的批处理

    最近在Java编程过程中,常用到dos窗口对程序进行编译与运行.但是不方便之处在于每次都要输入命令进入将要编译的程序的目录(其实也有简单的方法,在文章末尾给出).于是编写了一个配置文件,可以一次修改, ...

  7. ActiveMQ系列之二:ActiveMQ安装和基本使用

    下载并安装ActiveMQ服务器端 1:从http://activemq.apache.org/download.html下载最新的ActiveMQ 2:直接解压,然后拷贝到你要安装的位置就好了 启动 ...

  8. Android特效专辑(六)——仿QQ聊天撒花特效,无形装逼,最为致命

    Android特效专辑(六)--仿QQ聊天撒花特效,无形装逼,最为致命 我的关于特效的专辑已经在CSDN上申请了一个专栏--http://blog.csdn.net/column/details/li ...

  9. 面试之路(29)-TCP流量控制和拥塞控制-滑动窗口协议详解

    拥塞: 拥塞发生的主要原因在于网络能够提供的资源不足以满足用户的需求,这些资源包括缓存空间.链路带宽容量和中间节点的处理能力.由于互联网的设计机制导致其缺乏"接纳控制"能力,因此在 ...

  10. Redis的集群配置

    如果我们redis的压力很大,如果我们的并发高到我们读数据和写数据都有了很大压力. 那么我们可能就需要把redis分开部署,并且配置为一个『主从』的状态. 在服务器上构筑Redis的集群配置: 1.切 ...