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. strutsCRUD

    Bookdao public class BookDao extends JsonBaseDao{ //分页查询书本信息 //根据书本id查询当个书本信息 public List<Map< ...

  2. C语言指针的使用例子(1)指针地址的输出

    #include <stdio.h> int main(void) { int a=10; int *p = &a; *p = 89; printf("变量值a=%d a ...

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

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

  4. [SCOI2005][BZOJ 1084]最大子矩阵

    Description 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. Input 第一行为n,m,k(1≤n≤100,1≤m≤2 ...

  5. 浅谈python闭包及装饰器

    1. 什么是闭包: 闭包 是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变 ...

  6. jquery选择器(1)

    jQuery 元素选择器 jQuery 使用 CSS 选择器来选取 HTML 元素. $("p") 选取 <p> 元素. $("p.intro") ...

  7. arts打开第11周

    给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 示例 1: 输入: "A man, a plan, a c ...

  8. python操作toml文件

    # -*- coding: utf-8 -*- # @Time : 2019-11-18 09:31 # @Author : cxa # @File : toml_demo.py # @Softwar ...

  9. F5健康检查导致的服务端连接异常RST

    1. TCP健康检查 比如阿里云,F5负载设备当前都有这种机制. 该实现机制可能会导致后端ECS认为相关TCP连接出现异常(非正常退出),并在业务软件如Java连接池等日志中抛出相应的错误信息,如Co ...

  10. 009 轮播图,offset系列

    关于使用JS做轮播图,使用一个章节进行笔迹. 一:简单轮播图 1.程序 <!DOCTYPE html> <html lang="en"> <head& ...