Java基础教程:垃圾回收

垃圾回收

  垃圾回收(Garbage Collection,GC),顾名思义是释放垃圾占用的空间,防止内存泄漏。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收

  认定垃圾时有两种主要算法:引用计数法、可达性分析算法。

引用计数法

  引用计数法(Reachability Counting)是通过在对象头中分配一个空间来记录该对象被引用的次数(Reference Count)。如果该对象被其他对象引用,则它的引用计数就加一,如果一个删除对该对象的引用,那么他的引用计数就减,当一个对象的引用计数为0时,那么该对象就会被回收

  如String m = new String("jack"),jack字符串有一个引用,就是m:

   

  将m设置为null,这时候jack的引用次数为0,意味着这块内容要被回收了。

  

  但是引用计数法无法解决循环依赖问题,比如 a.value = b;b.value =a ;这样相会引用,导致它们永远不会被回收。

可达性分析算法

  可达性分析算法(Reachability Analysis)的基本思路是,通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连时(即从 GC Roots 节点到该节点不可达),则证明该对象是不可用的

  

  通过可达性分析算法,成功解决了引用计数无法解决的“循环依赖”问题。只要你无法与 GC Root 建立直接或间接的连接,系统就会判定你为可回收对象。

  在Java语言中,可作为GC Root的对象包括以下四种:

  • 虚拟机栈中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象  

怎么回收垃圾

  在确定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是开始进行垃圾回收,但是这里面涉及到一个问题是:如何高效地进行垃圾回收。由于Java虚拟机规范并没有对如何实现垃圾收集器做出明确的规定,因此各个厂商的虚拟机可以采用不同的方式来实现垃圾收集器,这里我们讨论几种常见的垃圾收集算法的核心思想。

标记清除

  

  标记清除算法(Mark-Sweep),先对即可回收的垃圾进行标记,然后清理掉,就像上图一样,清理掉的垃圾就变成未使用的内存区域,等待被再次使用。逻辑很清晰,但是它存在一个很大的问题,那就是内存碎片。会导致我们想要一个连续的大一点的空间,但是被分散在各个地方,无法申请到。

复制

  

  复制算法(Copying)是在标记清除算法上演化而来,解决标记清除算法的内存碎片问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。保证了内存的连续可用,内存分配时也就不用考虑内存碎片等复杂情况,逻辑清晰,运行高效。

  但是它也有一个问题,就是空间必须拆分,即你有10G内存,但是能分配的最大单个对象只有5G。

标记整理

  

  标记整理算法(Mark-Compact)标记过程仍然与标记 --- 清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,再清理掉端边界以外的内存区域

  它仍然有一个致命问题,就是效率问题,它对内存变动更频繁,需要整理所有存活对象的引用地址,在效率上比复制算法要差很多

分代收集算法

  分代收集算法(Generational Collection)严格来说并不是一种思想或理论,而是融合上述3种基础的算法思想,而产生的针对不同情况所采用不同算法的一套组合拳。对象存活周期的不同将内存划分为几块。一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记-清理或者标记整理算法来进行回收

Java堆的结构

  

  Java堆分为两个区域,年轻代和老年代,其中年轻代又分为Eden区和Survivor,Survivor分为Form 和To 两个区。

Eden

  大多数情况下,对象会在新生代Eden区中进行分配,当Eden区没有足够空间进行分配时,虚拟机会发起一次Minor GC,Minor GC相比Major GC更频繁,回收速度也更快。

  通过Minor GC之后,Eden会被清空,Eden区中绝大多数对象会被回收,而那些无需回收的存活对象,就会进入Survivor的Form区,若Form区不够,则直接进入Old区。

Survivor

  Survivor区相当于Eden区与Old区的一个缓存,类似我们交通灯中的黄灯。Survivor区存在的意义就是减少被送到老年区的对象,从而减少Major GC的发生。Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才能被送到老年代。Survivor设置两个的原因是,Survivor内部使用特殊的清理算法(类似于复制算法),可以解决内存碎片化。

Old

  老年代占据着2/3的堆内存空间,只有在Major GC的时候才会进行清理。在老年代,对象存活率很高,如果复制的话很麻烦,采用标记整理算法较好。

特殊情况

  大对象是需要大量连续内存空间的对象,这部分对象直接进入老年代。

参考链接

  • https://mp.weixin.qq.com/s/v7hXr1RHKJpS20LxctvCFg
  • 《深入理解Java虚拟机》。

Java基础教程:垃圾回收的更多相关文章

  1. Java基础教程——垃圾回收机制

    垃圾回收机制 Garbage Collection,GC 垃圾回收是Java的重要功能之一. |--堆内存:垃圾回收机制只回收堆内存中对象,不回收数据库连接.IO等物理资源. |--失去使用价值,即为 ...

  2. java基础之 垃圾回收机制

    1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的 ...

  3. Java基础之垃圾回收

    /** * 对象在没有任何引用可以到达时,生命周期结束,成为垃圾. * 所有对象在被回收之前都会自动调用finalize()方法. * ******************************** ...

  4. Java基础教程:面向对象编程[1]

    Java基础教程:面向对象编程 内容大纲 Java语言概述 Java语言特点 1.Java为纯面向对象的语言,它能够直接反映现实生活中的对象.总之,Everything is object! 2.平台 ...

  5. Java基础教程:Java内存区域

    Java基础教程:Java内存区域 运行时数据区域 Java虚拟机在执行Java程序的过程种会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟 ...

  6. Java GC(垃圾回收)机制知识总结

    目录 Java GC系列 Java关键术语 Java HotSpot 虚拟机 JVM体系结构 Java堆内存 启动Java垃圾回收 Java垃圾回收过程 垃圾回收中实例的终结 对象什么时候符合垃圾回收 ...

  7. Java编程思想学习笔记_1(Java内存和垃圾回收)

    1.Java中对象的存储数据的地方: 共有五个不同的地方可以存储数据. 1)寄存器.最快,因为位于处理器的内部,寄存器按需求分配,不能直接控制. 2)堆栈.位于通用RAM,通过堆栈指针可以从处理器那里 ...

  8. Java虚拟机之垃圾回收详解一

    Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...

  9. JVM基础(5)-垃圾回收机制

    一.对象引用的类型 Java 中的垃圾回收一般是在 Java 堆中进行,因为堆中几乎存放了 Java 中所有的对象实例.谈到 Java 堆中的垃圾回收,自然要谈到引用.在 JDK1.2 之前,Java ...

随机推荐

  1. WAMP 403 Forbidden禁止访问,别的电脑访问不了;

    直接上图: 1:修改httpd.conf; deny from all 改成------ allow from all 重启服务就好了: 2:如果搜不到deny from all 就按照下面的方法来 ...

  2. bash: cd: too many arguments 报错

    路径名或者变量有空格时候,会造成参数太多的错误提示 解决方法:把空格的地方用引号包括起来

  3. golang-切片copy

    package main import ( "fmt" ) func main() { fmt.Println("-------------") data := ...

  4. 在Android Studio中找不到AppCompatActivity解决方案

    在创建新的.java文件时,要导入父类中的 AppCompatActivity,报错,无法找到这个父类. 解决方案:   1.先找到“project structure”,然后app--Depende ...

  5. 模板 - 图论 - 强连通分量 - Kosaraju算法

    这个算法是自己实现的Kosaraju算法,附带一个缩点,其实缩点这个跟Kosaraju算法没有什么关系,应该其他的强连通分量算法计算出每个点所属的强连通分量之后也可以这样缩点. 算法复杂度: Kosa ...

  6. input的禁止标签

    <body> <input type="text" name="" value="你好" disabled="d ...

  7. shell文本处理工具

    本文将介绍Linux下使用Shell处理文本时最常用的工具: find.grep.xargs.sort.uniq.tr.cut.paste.wc.sed.awk: 提供的例子和参数都是最常用和最为实用 ...

  8. css设置使文字显示2行多余的为省略号...

    1 2 3 4 5 6 7 8 9 10 11 12 .title{        font-size: .7rem;        line-height: 1.5rem;          ove ...

  9. PHP用strtotime()函数比较两个时间的大小实例详解

    在PHP开发中,我们经常会对两个时间的大小进行判断,但是,在PHP中,两个时间是不可以直接进行比较,因为时间是由年.月.日.时.分.秒组成的,所以,如果需要将两个时间进行比较的话,我们首先要做的就是将 ...

  10. mongodb批量update更新数据

    需要先查找出相关的记录,然后循环处理更新数据.如下案例,更新所有status=1的数据的gender值为2 db.getCollection('test').find({"status&qu ...