通常来说,要写Java代码,你基本上都没必要听说垃圾回收这个概念的。这不,对于已经写了多年Java代码的我来说,我还没有哪次经历说是需要使用垃圾回收方面的知识来解决问题的。但是,我依然督促自己花了几天时间系统性地(也比较浅显地)学习了Java垃圾回收机制。我认为学习Java垃圾回收机制至少可以得到以下几方面的好处:

  1. 对于系统调优有直接帮助
  2. 增加和同行聊天或者下一份工作面试时的谈资
  3. 在追求技术卓越上更进一步

(一)Java堆内存的分代管理

Java垃圾回收是需要消耗CPU和内存资源的,其速度随着内存的变大而减慢,这将严重影响系统的性能。同时,Java系统中存在着这么一种现象:大多数Java对象都是“短命”的。基于此,Java采用了分代的内存管理方式,并在不同的内存代中采用不同的垃圾回收算法,从而达到对内存更细粒度的管理,最大限度地减小垃圾回收对系统本身的影响。

 
 
 
 
由上图所示,Java的堆空间被分为了三个区域,分别是新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation)。新创建出来的对象首先存放在新生代,经过新生代中多次垃圾回收(在Survivor 0和Survivor 1之间来回复制),存活下来的对象将被转移到老年代。新生代中垃圾回收很频繁,这样多数“短命”的对象将得到及时清理;又由于新生代内存空间通常不大,回收速度也相对较快。在老年代中,存放着从新生代中经历了多次垃圾回收后仍然存活的对象,这些对象相对较少,而老年代内存一般很大,并不容易塞满,因此老年代的垃圾回收频率要远远低于新生代,从而减少了对系统性能的影响。永久代中主要存放Java类本身的数据信息,当Java类不再被使用时,也会被垃圾回收掉。开发者们通常无法预测永久代的大小,导致程序经常出现 “java.lang.OutOfMemoryError: Permgen space”错误,因此在Java 8中,使用jvm进程原生内存空间的Metaspace代替了永久代。在默认情况下,Metaspace将使用jvm进程所有可用的内存。 
 
在新生代进行的GC叫做minor GC,在老年代进行的GC都叫major GC,Full GC同时作用于新生代和老年代。在垃圾回收过程中经常涉及到对对象的挪动(比如上文提到的对象在Survivor 0和Survivor 1之间的复制),进而导致需要对对象引用进行更新。为了保证引用更新的正确性,Java将暂停所有其他的线程,这种情况被称为“Stop-The-World”,导致系统全局停顿。Stop-The-World对系统性能存在影响,因此垃圾回收的一个原则是尽量减少“Stop-The-World”的时间。
 
 
 
 
上图展示了不同垃圾收集器的Stop-The-World情况,可以看出Serial、Parallel和CMS收集器均存在不同程度的Stop-The-Word情况;而即便是最新的G1收集器也不例外。
 
 
(二)垃圾回收算法
 
最早的垃圾回收算法有引用计数法,但由于其性能不好以及无法回收循环引用对象的问题,工程上并没有得到使用。当前Java的垃圾回收主要基于标记-清除(Mark-Sweep)算法,该算法大致包括两个步骤:
  1. 从GC ROOT对象开始标记所有可达对象,GC ROOT包括局部变量、静态变量及运行中的线程对象等。
  2. 清除掉未被标记的对象
标记-清除算法是Java垃圾回收的基本原则,在此基础上,Java还提供了几种变种算法,包括标记-压缩(Mark-Sweep-Compact)算法和标记-复制(Mark-Copy)等。
 
 
标记清除算法(Mark Sweep)
标记清除算法的原理即上文中提到的两个步骤,这种算法的优点是可以减少Stop-The-World的时间,缺点是会造成内存碎片,如下图所示:
 
 
 
 

标记压缩算法(Mark Sweep Compact)

为了解决内存碎片问题,标记压缩算法(如下图所示)在回收内存之后会将存活的对象集体压到内存的一端。压缩过程需要更新对象的引用,如前文所述,这将增加系统Stop-The-World时间。

标记复制算法(Mark Copy)

标记复制算法是一种效率相对较高的算法,因为它不涉及对无用对象的删除,只需要将标记存活的对象从一个内存区拷贝到另一个内存区。但是标记复制算法不适用于存活对象较多的老年代,因为大量的对象拷贝会降低系统性能。Java在新生代中主要采用了标记复制算法,其中包括从Eden区到Survivor区的复制和两个Survivor区之间的复制。

 
 
(三)垃圾收集器
 
在Java中主要有4种垃圾收集器,他们各自对于不同的内存代采用不同的算法。Java会根据当前系统的基本配置确定一个默认的垃圾收集器,你可以通过以下命令查看:
 
java -XX:+PrintCommandLineFlags -version

在笔者的电脑上输出为:

-XX:InitialHeapSize=268435456 -XX:+PrintCommandLineFlags -XX:+UseParallelGC
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

由红色部分可以看出,默认情况下使用了Parallel收集器,这也是多数Java机器(特别是服务器)默认的垃圾收集器。

串行收集器(Serial Collector)

顾名思义,串行收集器指采用单线程进行垃圾回收,回收时会导致长时间的Stop-The-World,主要用于单机程序。该收集器在新生代采用复制算法,在老年代采用标记-压缩算法。可以通过-XX:+UseSerialGC命令行选项激活该收集器。

 
 
并行收集器(Parallel Collector)
该收集器同样在新生代采用复制算法,在老年代采用标记-压缩算法,只是使用了多线程的方式进行垃圾回收,从而大大提高了回收效率,但是回收过程中同时需要Stop-The-World。可以通过-XX:+UseParallelGC激活该收集器。多数情况下,并行收集器是Java的默认收集器。
 
 
并发标记清除收集器(Concurrent Mark Sweep Collector,CMS)
该收集器在在新生代中采用复制算法,在老年代采用标记-清除算法(不是标记-压缩)。之所以叫“并发”,是因为在回收过程的某些阶段,回收线程和用户线程同时执行,当然不是整个回收过程都可以和用户线程并行的,该收集器也存在Stop-The-World的时候,只是相比于其他收集器来说Stop-The-World持续时间较少而已。可以通过-XX:+UseConcMarkSweepGC激活该收集器。
 
 
G1收集器(Garbage First Collector)
 G1收集器是Java世界最新的收集器,在Java 9中,它将成为默认的垃圾收集器。该收集器采用与上文中提到的收集器不同方式来对待Java对内存,如下图所示。可以通过-XX:+UseG1GC激活该收集器。
 
 
 
 

Java垃圾回收学习笔记的更多相关文章

  1. JAVA 垃圾回收读书笔记

    对象已死 在JAVA代码运行中,会不停的创建对象,因为内存空间不是无限的,Java虚拟机必须不停的回收无用的数据空间.那么虚拟机是怎么判断对象空间是需要被回收的呢,也就是怎么样的数据算是垃圾数据呢? ...

  2. java垃圾回收学习

    经过一个晚上的努力终于完成了一个文件替换指定字符串的程序,但是由于我要替换的全站程序html文件太多, 所以eclipse下边老是在一个目录结束后报出java.lang.OutOfMemoryErro ...

  3. java垃圾回收机制学习总结

    最近学习了一下java垃圾回收机制,将其主要内容大致总结一下: 1.什么是垃圾回收机制 java GC机制(garbage collection,垃圾收集,垃圾回收),是java特有的机制,作为jav ...

  4. 《深入理解Java虚拟机》学习笔记

    <深入理解Java虚拟机>学习笔记 一.走近Java JDK(Java Development Kit):包含Java程序设计语言,Java虚拟机,JavaAPI,是用于支持 Java 程 ...

  5. 《深入理解 Java 虚拟机》学习笔记 -- 内存区域

    <深入理解 Java 虚拟机>学习笔记 -- 内存区域 运行时数据区域 主要分为 6 部分: 程序计数器 虚拟机栈 本地方法栈 Java 堆 方法区 如图所示: 1. 程序计数器(线程私有 ...

  6. Java:NIO 学习笔记-1

    Java:NIO 学习笔记-1 说明:本笔记是根据bilibili上 尚硅谷 的课程 NIO视频 而做的笔记 主要内容 Java NIO 简介 Java NIO 与 IO 的主要区别 缓冲区(Buff ...

  7. Java GC系列(2):Java垃圾回收是如何工作的?

    本文由 ImportNew - 伍翀 翻译自 javapapers. 目录 垃圾回收介绍 垃圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 本教程是为了理解基本的Java垃圾回收以及它是如何 ...

  8. [牛感悟系列]JAVA(1)理解JAVA垃圾回收

    理解JAVA垃圾回收的好处是什么?满足求知欲是一方面,编写更好的JAVA应用是另外一方面. 如果一个人对垃圾回收过程感兴趣,那表明他在应用程序开发领域有相当程度的经验.如果一个人在思考如何选择正确的垃 ...

  9. [译]GC专家系列2:Java 垃圾回收的监控

    原文链接:http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/ 这是"成为GC专家系 ...

随机推荐

  1. JavaScript对象属性的基础教程指南

    JavaScript是使用“对象化编程”的,或者叫“面向对象编程”的.所谓“对象化编程”,意思是把JavaScript能涉及的范围划分成大大小小的对象,对象下面还继续划分对象直至非常详细为止,所有的编 ...

  2. js原生设计模式——3简单工厂模式\简单工厂模式封装简单对象

    1.Factory基本写法 <!DOCTYPE html><html lang="en"><head>    <meta charset= ...

  3. document.form.command.value

    问题:在一个JSP页面中需要多个提交按钮,每个按钮点击后需要把同一个form提交到不同的页面进行处理 解决:用JS. <html><head><title>一个表单 ...

  4. ThinkPHP 模板的包含、渲染、继承

    一.模板包含        <include file="完整模板文件名" />        <include file="./Tpl/default ...

  5. Netty学习笔记

    一些类与方法说明 1)ByteBuf ByteBuf的API说明: Creation of a buffer It is recommended to create a new buffer usin ...

  6. java文件上传(单文件 多文件)与删除

    /** * 文件上传--单文件 * * @param request * @param response * @param path * 文件存放路径(path为WebApp\后面的内容) * @re ...

  7. [html5] 学习笔记-响应式布局

    1.响应式布局介绍 响应式布局是2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端——而不是每一个终端做一个特定的版本.这个概念是为了兼容移动互联网浏览而诞生的,其目的是为用户提供 ...

  8. http-server 使用介绍

    做一个项目的时候需要服务环境,又不想使用apache,php,于是找到一款比较简单的易用的webserver 就是http-server 首先介绍一个怎么使用吧,http-server 是基于node ...

  9. Wireshark网络抓包(四)——工具

    一.基本信息统计工具 1)捕获文件属性(Summary) 1. File:了解抓包文件的各种属性,例如抓包文件的名称.路径.文件所含数据包的规模等信息 2. Time:获悉抓包的开始.结束和持续时间 ...

  10. 蓝桥网试题 java 基础练习 分解质因数

    -------------------------------------------------------------------------- 递归更多的用在多分支情况中 本题用循环就可以了 用 ...