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. MongoDB 复制集监控

    1.复制集状态查询:rs.status() 2.查看当前副本集oplog状态:rs.printReplicationInfo() 3.查看复制延迟:rs.printSlaveReplicationIn ...

  2. Oracle 重新编译存储过程/函数等

    第一种  如果你使用 PL/SQL Developer工具          左侧工具栏中选择“存储过程”->选择已经失效的procedure->右键->选择重新编译 即可完成 第二 ...

  3. Kubernetes 学习20调度器,预选策略及优选函数

    一.概述 1.k8s集群中能运行pod资源的其实就是我们所谓的节点,也称为工作节点.master从本质上来讲,他其实是运行整个集群的控制平面组件的比如apiserver,scheal,controlm ...

  4. IP地址与Mac地址绑定错误

    有个application,有时候可以正常访问,有时候又返回404错误,百思不得其解.刚开始以为是文件夹权限问题,折腾了好久. 后来没在服务器上monitor到包,所以猜想是到了错误的mac地址,用a ...

  5. win10 安装Borland C++Builder 6后编译运行出

    win10系统安装bcb后打开bcb后显示 Unable to rename ‘c:\Program Files(x86)\Borland\CBuilder6\Bin\bcb.$$$'to‘cc:\P ...

  6. 【一起来烧脑】一步React.JS学会体系

    [外链图片转存失败(img-cn4fbVDq-1563575047348)(https://upload-images.jianshu.io/upload_images/11158618-8c6f3d ...

  7. (8)打鸡儿教你Vue.js

    监听属性 监听属性 watch 通过 watch 来响应数据的变化 <div id = "app"> <p style = "font-size:25p ...

  8. vimset

    vim ~./vimrc  vim /etc/vim/vimrc set nocompatible                 "去掉有关vi一致性模式,避免以前版本的bug和局限 se ...

  9. 1066 Root of AVL Tree (25)

    An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...

  10. 安装 sqoop

    简介 Sqoop是一个用来将Hadoop(Hive.HBase)和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库(例如:MySQL ,Oracle ,Postgres等)中的数据导入到Ha ...