主要参考和复制粘贴

本文原创作者:书呆子Rico
作者博客地址:http://blog.csdn.net/justloveyou_/


一、 用来干什么

java 的垃圾回收机制是为了自动收回已经没有用的内存空间。比如说下面的例子:

dog doga;
doga = new dog("路马");

这个语句的第一行创建了一个对 dog 类对象的引用,即 doga (注意,它只是引用不是对象)。doga存储在虚拟机栈中。

第二行代码使用new语句在java堆中开辟内存空间,创建了一个对象,并使用 doga 引用该对象。

java回收机制就是为了回收第二行代码在堆中创建的对象,当没有类似 doga 这样的对象引用来引用路马这个对象的时候,java就会自动去回收该对象在堆中占用的内存,以便程序接下来使用。比如说

dog doga;
doga = new dog("路马");
doga = null

上面这个例子的第三行代码里,doga 指向了Null, 这个时候没有任何的对象引用指向"路马"这个对象,此时“路马”这个对象就会被java自动回收。如果此时没有被回收,那就会出现内存泄漏


内存泄露 指内存空间使用完毕之后未回收。一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度。


二、 java如何检测哪些对象应该被回收?

可达性分析算法:判断对象的引用链是否可达

 可达性分析算法是通过判断对象的引用链是否可达来决定对象是否可以被回收。

 可达性分析算法是从图论引入的,程序把所有的引用关系看作一张图,通过一系列的 “GC Roots” 作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain)。
 当一个对象到 GC Roots 没有任何引用链相连(用图论的话来说就是从 GC Roots 到这个对象不可达)时,则证明此对象是不可用的。
 在Java中,GC Root就是对象的引用。可作为 GC Root 的对象引用 包括以下几种:

  • 虚拟机栈(栈帧中的局部变量表)中的引用;
  • 方法区中类静态属性的引用;
  • 方法区中常量引用;
  • 本地方法栈中Native方法引用;

三、 java如何回收垃圾内存 - 垃圾收集算法

  1. 标记清除算法
      标记-清除算法分为标记和清除两个阶段。该算法首先从根集合进行扫描,对存活的对象对象标记,标记完毕后,再扫描整个空间中未被标记的对象并进行回收,如下图所示。
      
    标记-清除算法的主要不足有两个:
      效率问题:标记和清除两个过程的效率都不高;
      空间问题:标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,因此标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

  2. 复制算法
      复制算法将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这种算法适用于对象存活率低的场景,比如新生代。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。该算法示意图如下所示:
      
      事实上,现在商用的虚拟机都采用这种算法来回收新生代。因为研究发现,新生代中的对象每次回收都基本上只有10%左右的对象存活,所以需要复制的对象很少,效率还不错。
      使用内存时,会将新生代内存分为一块较大的Eden空间和两块较小的Survivor空间 (survivor1 和 survivor2),每次使用Eden和其中一块Survivor。
      回收内存时,将Eden和Survivor中还存活着的对象一次地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。
      HotSpot虚拟机默认Eden和Survivor的大小比例是 8:1,也就是每次新生代中可用内存空间为整个新生代容量的90% ( 80%+10% ),只有10% 的内存(没有被用的那一个survivor)会被“浪费”。

  3. 标记整理算法
      复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。标记整理算法的标记过程类似标记清除算法,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存,类似于磁盘整理的过程,该垃圾回收算法适用于对象存活率高的场景(老年代),其作用原理如下图所示。         
    tip
      标记整理算法与标记清除算法最显著的区别是:标记清除算法不进行对象的移动,并且仅对不存活的对象进行处理;而标记整理算法会将所有的存活对象移动到一端,并对不存活对象进行处理,因此其不会产生内存碎片。标记整理算法的作用示意图如下:

  4. 分代收集算法
      对于一个大型的系统,当创建的对象和方法变量比较多时,堆内存中的对象也会比较多,如果逐一分析对象是否该回收,那么势必造成效率低下。分代收集算法是基于这样一个事实:不同的对象的生命周期(存活情况)是不一样的,而不同生命周期的对象位于堆中不同的区域,因此对堆内存不同区域采用不同的策略进行回收可以提高 JVM 的执行效率。
      当代商用虚拟机使用的都是分代收集算法:新生代对象存活率低,就采用复制算法;老年代存活率高,就用标记清除算法或者标记整理算法。Java堆内存一般可以分为新生代、老年代和永久代三个模块,如下图所示:
      
    1). 新生代(Young Generation)
      新生代的目标就是尽可能快速的收集掉那些生命周期短的对象,一般情况下,所有新生成的对象首先都是放在新生代的。新生代内存按照 8:1:1 的比例分为一个eden区和两个survivor(survivor0,survivor1)区,大部分对象在Eden区中生成。在进行垃圾回收时,先将eden区存活对象复制到survivor0区,然后清空eden区,当这个survivor0区也满了时,则将eden区和survivor0区存活对象复制到survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后交换survivor0区和survivor1区的角色(即下次垃圾回收时会扫描Eden区和survivor1区),即保持survivor0区为空,如此往复。
      特别地,当survivor1区也不足以存放eden区和survivor0区的存活对象时,就将存活对象直接存放到老年代。如果老年代也满了,就会触发一次FullGC,也就是新生代、老年代都进行回收。注意,新生代发生的GC也叫做MinorGC,MinorGC发生频率比较高,不一定等 Eden区满了才触发。
      
    2). 老年代(Old Generation)
      老年代存放的都是一些生命周期较长的对象,就像上面所叙述的那样,在新生代中经历了N次垃圾回收后仍然存活的对象就会被放到老年代中。此外,老年代的内存也比新生代大很多(大概比例是1:2),当老年代满时会触发Major GC(Full GC),老年代对象存活时间比较长,因此FullGC发生的频率比较低。
      
    3). 永久代(Permanent Generation)
      永久代主要用于存放静态文件,如Java类、方法等。永久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如使用反射、动态代理、CGLib等bytecode框架时,在这种时候需要设置一个比较大的永久代空间来存放这些运行过程中新增的类。

  5. 垃圾回收算法总结
     由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。垃圾回收有两种类型,Minor GC 和 Full GC。

    Minor GC:对新生代进行回收,不会影响到年老代。因为新生代的 Java 对象大多死亡频繁,所以 Minor GC非常频繁,一般在这里使用速度快、效率高的算法,使垃圾回收能尽快完成。
     
    Full GC:也叫 Major GC,对整个堆进行回收,包括新生代和老年代。由于Full GC需要对整个堆进行回收,所以比Minor GC要慢,因此应该尽可能减少Full GC的次数,导致Full GC的原因包括:老年代被写满、永久代(Perm)被写满和System.gc()被显式调用等。

四、JAVA仍然有可能出现内存泄漏

虽然Java拥有垃圾回收机制,但同样会出现内存泄露问题,比如下面提到的几种情况:

(1). 诸如 HashMap、Vector 等集合类的静态使用最容易出现内存泄露,因为这些静态变量的生命周期和应用程序一致,所有的对象Object也不能被释放,因为他们也将一直被Vector等应用着。

private static Vector v = new Vector(); public void test(Vector v){for (int i = 1; i<100; i++) { Object o = new Object(); v.add(o); o = null; }
}

在这个例子中,虚拟机栈中保存者 Vector 对象的引用 v 和 Object 对象的引用 o 。在 for 循环中,我们不断的生成新的对象,然后将其添加到 Vector 对象中,之后将 o 引用置空。问题是虽然我们将 o 引用置空,但当发生垃圾回收时,我们创建的 Object 对象也不能够被回收。因为垃圾回收在跟踪代码栈中的引用时会发现 v 引用,而继续往下跟踪就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。也就是说,尽管o 引用已经被置空,但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将其释放掉。如果在此循环之后, Object 对象对程序已经没有任何作用,那么我们就认为此 Java 程序发生了内存泄漏。

(2). 各种资源连接包括数据库连接、网络连接、IO连接等没有显式调用close关闭,不被GC回收导致内存泄露。

(3). 监听器的使用,在释放对象的同时没有相应删除监听器的时候也可能导致内存泄露。

JAVA垃圾回收机制-精简版相关推荐

  1. 1024节日快乐!——Java垃圾回收机制

    Java垃圾回收机制 要进行垃圾回收,最为重要的一个问题是:判断谁是垃圾? 联想其日常生活中,如果一个东西经常没被使用,那么这个对象可以说就是垃圾.在 Java 中也是如此,如果一个对象不可能再被引用 ...

  2. java垃圾回收机制_笔记 | Java垃圾回收机制

    本文经授权转载自程序员杂货铺(ID:speakFramework) 垃圾回收 最近上海的小伙伴是不是要被强垃圾分类搞疯了???哈哈哈哈 上海是个走在前列的城市啊,不光骑自行车闯红灯要被罚钱,垃圾不分类 ...

  3. Java垃圾回收机制(Garbage Collection)

    引用博客地址:http://www.cnblogs.com/ywl925/p/3925637.html 以下两篇博客综合描述Java垃圾回收机制 第一篇:说的比较多,但是不详细 http://www. ...

  4. java垃圾回收机制_JVM的垃圾回收机制——垃圾回收算法

    一.Java垃圾回收机制 在java中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行.在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者 ...

  5. 36.JVM内存分哪几个区,每个区的作用是什么、如和判断一个对象是否存活、java垃圾回收机制、垃圾收集的方法有哪些、java类加载过程、类加载机制、双亲委派、Minor GC和Major GC

    36.JVM内存分哪几个区,每个区的作用是什么? 37.如和判断一个对象是否存活?(或者GC对象的判定方法) 38.简述java垃圾回收机制? 39.java中垃圾收集的方法有哪些? 40.java类 ...

  6. 深入理解 Java 垃圾回收机制

    转载自 http://www.cnblogs.com/andy-zcx/p/5522836.html 深入理解 Java 垃圾回收机制 一:垃圾回收机制的意义 java  语言中一个显著的特点就是引入 ...

  7. java垃圾回收机制的理解

    Java垃圾回收机制算法 标记----清除算法 复制算法 标记----整理算法 分代收集算法 为什么要进行垃圾回收 因为当一个对象的引用不可达,或者一个对象没有任何引用指向它,那么它就没有必要在内存中 ...

  8. 【Java】Java垃圾回收机制

    Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给 ...

  9. Java深度历险(四)——Java垃圾回收机制与引用类型

    Java语言的一个重要特性是引入了自动的内存管理机制,使得开发人员不用自己来管理应用中的内存.C/C++开发人员需要通过malloc/free 和new/delete等函数来显式的分配和释放内存.这对 ...

最新文章

  1. Apache 'mod_accounting'模块SQL注入漏洞(CVE-2013-5697)
  2. mac里面如何复制路径
  3. jdbc连接mysql数据库的常用对象_JDBC常用对象
  4. js 删除服务器文件,Node.js复制/删除服务器端文件到指定目录文件夹下,并且预判是否存在该目录,如果没有,则递归创建该文件夹目录...
  5. java struts2国际化代码下载_【Java框架】java struts2框架中页面表示国际化的方法 - 思诚科技...
  6. 基于Geoserver配置多图层地图以及利用uDig来进行样式配置
  7. 大数据_Flink_数据处理_命令行提交Job---Flink工作笔记0014
  8. 蓝桥杯 ADV-69 算法提高 质因数
  9. 操作 SQL Server Mobile 2005 数据库的常用 C# 代码 (转自黎波)
  10. paip.提升开发效率---增量备份项目文件
  11. arraylist长度_面经手册 第7篇ArrayList也这么多知识?一个指定位置插入就把谢飞机面晕了!...
  12. 【操作系统】系统中断技术
  13. 使用Md5加密算法对密码进行加密(工具类)
  14. 安全测试(六)iOS ipa软件安全 APP应用安全 手机软件安全 ipa安全 ipa反编译 应用日志窃取 ipa漏洞 应用软件本身功能漏洞 iPhone移动应用常规安全讲解
  15. matlab生成的图片里怎么加入字体,Matlab,Visio等生成的图片的字体嵌入问题解决方法...
  16. CSS 之 后代、并列选择器
  17. 计算智能——K-均值算法
  18. 用户上传用户头像至服务器
  19. vue+elementUI同时上传视频和图片并回显
  20. 微信小程序 一键授权 给第三方平台代开发管理(二,一键授权给第三方平台)

热门文章

  1. 通讯录管理系统C++版
  2. 以太坊私链搭建(二)——genesis.json字段解读
  3. python编写的双击genesis2000导入tgz的脚本
  4. Linux | 新建虚拟硬盘并挂盘
  5. 腾讯、百度和360三大平台网站拦截误报申诉入口
  6. 基于ONNX的人物卡通化
  7. 智能催收取代人工催收只是噱头吗?
  8. vmware详细安装教程
  9. [嵌入式开发模块]GY25倾斜角度传感器 驱动模块
  10. 机器学习零基础初学者入门