二、垃圾收集器与内存分配策略

   前言:讨论的区域集中在Java堆和方法区中,而其他几个区域的内存分配和回收都具备确定性,所以不需过多考虑回收
的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。在开始讨论之前,我们先来了解一下GC的区域划分:大体可划分为:新生代(def new generation)、老年代(tenured generation)、持久代(也被叫做永久代、永久区)(compacting perm generation)然后新生代又可划分为一块较大的Eden空间和两块较小的Survivor空间,Survivor区可以继续划分为from区和to区那我们怎么样判断对象是处于哪个区域呢?我的理解就是:一个对象只要没有被回收一次,年龄就加一,然后我们可以通过年龄来判断属于哪个区域。

HotSpot虚拟机默认每一个Survivor区大概占新生代的1/10,Eden区占8/10

2.1、判断对象的情况

垃圾收集器在对堆进行回收前,第一件事就是要确定这些对象之中那些还“存活”着,哪些已经“死去”。

2.1.1 引用计数算法

 很多教科书判断对象是否存活的算法:给对象添加一个引用计数器,每当有一个地方引用它,计数器值就加1;引用
失效时,值就减1;任何时刻计数器为0的对象就是不可能再被使用的。但是主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引
用的问题。下面这个例子就是如此,此时da和db两个对象已经不可能再被访问了,但是它们因为互相引用着对方,导致它们的引
用计数都不为0,于是引用计数算法无法通知GC收集器去回收它们。


控制台中的GC日志显示"4704K->515K",意味着虚拟机并没有因为这两个对象互相引用就不回收它们,这也从侧面说明虚拟机并不是通过引用计数算法来判断对象是否存活的。

4704K->515K(7680K), 0.0038929 secs  的的含义:
GC前该内存区域已使用内存->GC后该内存区域使用容量(该内存区域总容量),GC所用的时间

还有一些其他的含义大家可以自行百度。

2.1.2 可达性分析算法


目前主流的商用语言(Java、C#)都是通过可达性分析来判定对象是否存活的。如图,此算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连(用图论的话来说,就是从 GC Roots 到这个对象不可达)时,则证明此对象是不可用的。对象object5、6、7虽然互相有关联,但是它们到 GC Roots 是不可达的,所以它们将会被判定为是可回收的对象。

Java语言中,可作为 GC Roots 的对象包括下面几种:1、虚拟机栈(栈帧中的本地变量表)中引用的对象。2、方法区中类静态属性引用的对象。3、方法区中常量引用的对象。4、本地方法栈中JNI(即一般说的 Native 方法)引用的对象。

2.1.3 四种引用

   1、强引用:就平时经常用到的,类似“Object obj = new Object()” 这类的引用,只要强引用还存在,垃圾收集器
永远不会回收掉被引用的对象。2、软引用:描述一些还有用但并非必需的对象。在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中
进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。3、弱引用:强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,
无论当前内存是否足够,都会回收掉只被弱引用关联的对象。4、虚引用:也被称作幽灵引用或者幻影引用,非常非常弱的引用关系。完全不会对对象的生存时间构成影响,也无法通
过虚引用来取得一个对象实例。那虚引用的目的在哪呢?就是能在这个对象被收集器回收时收到一个系统通知。

2.1.4 回收方法区

   虽然方法区(或者HotSpot虚拟机中的永久代)垃圾收集效率很低,但其实也是存在的。方法区(永久代)主要回收两部分内容:废弃常量和无用的类。1、废弃常量:没有其他地方引用了这个字面量就回收2、无用的类:①该类所有实例都被回收,也就是堆中不存在该类的任何实例。②加载该类的 ClassLoader 已经被回收。③该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。满足上面三个条件就可以进行无用类的回收了,但也仅仅是“可以”,是否对其进行回收,虚拟机提供了一些相关的参数。在大量使用反射、动态代理、CGLib等ByteCode框架、动态生成JSP以及OSGi这类频繁自定义ClassLoader的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出。

2.2 垃圾收集算法

因为垃圾收集算法涉及大量的程序细节,而且各个平台的虚拟机操作内存的方法又各不相同,这里只简单的介绍几种算法的思想及其发展过程。

2.2.1 标记–清除算法

 这个算法是最基础的收集算法,如同其名,先标记再清除。首先标记需要回收的对象,然后再统一进行清除。至于为什
么说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其不足进行改进而得到的。主要不足有两点:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,如上图所示,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

2.2.2 复制算法

 下面是我对复制算法的总结:目的:解决效率问题。过程:将可用内存按容量划分为大小两块,如上图所示,一块是保留紫色的保留区域,其他部分就是另外一块。我们可以看到上图的“回收前状态”,当表格的左半边区域内存使用完时,虚拟机会先把左边还存活着的对象复制到右半边的保留区域,并且按顺序排好,然后会把左边已使用过的内存空间一次性全部清理掉。优点:每次只对一半的区域进行内存回收,内存分配时也不用考虑内存碎片等复杂情况,只需要移动存活着的对象堆顶的指针,将其按顺序分配内存即可。实现简单,运行高效。缺点:将内存缩小为原来的一半,未免太高了些。但是在新生代中可以避免这个缺点(具体原因												

《深入理解JAVA虚拟机》学习日志----一、自动内存管理机制(2.垃圾收集器与内存分配策略)相关推荐

  1. Java虚拟机学习(3): 类加载机制

    类加载机制 JVM把class文件加载的内存,并对数据进行校验.转换解析和初始化,最终形成JVM可以直接使用的Java类型的过程就是加载机制. 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命 ...

  2. 深入理解JAVA虚拟机学习笔记(一)JVM内存模型

    摘要:   上周末搬家后,家里的宽带一直没弄好,跟电信客服反映了N遍了终于约了个师傅明天早上来迁移宽带,可以结束一个多星期没网的痛苦日子了.这段时间也是各种忙,都一个星期没更新博客了,再不写之前那种状 ...

  3. 【深入理解Java虚拟机学习笔记】第三章 垃圾收集器与内存分配策略

    最近想好好复习一下java虚拟机,我想通过深读 [理解Java虚拟机 jvm 高级特性与最佳实践] (作者 周志明) 并且通过写一些博客总结来将该书读薄读透,这里文章内容仅仅是个人阅读后简短总结,加强 ...

  4. 【深入理解Java虚拟机学习笔记】第二章 Java 内存区域与内存溢出异常

    最近想好好复习一下java虚拟机,我想通过深读 [理解Java虚拟机 jvm 高级特性与最佳实践] (作者 周志明) 并且通过写一些博客总结来将该书读薄读透,这里文章内容仅仅是个人阅读后简短总结,加强 ...

  5. java 准备 解析_深入理解JAVA虚拟机学习笔记24——类加载的准备和解析

    每天进步一点点! 今天我们一起看一下类加载的准备阶段和解析阶段. 先看一下准备阶段:主要任务是在方法区中为类变量(仅static修饰变量,不包含实例变量)分配内存并设置类变量初始化的阶段. 这里面的区 ...

  6. 深入理解Java虚拟机学习笔记-1.JVM内存模型

    JVM内存模型 1.内存模型结构图 名称 特征 作用 配置参数 异常 程序计数器 占用内存小,线程私有, 生命周期与线程相同 大致为字节码行号指示器 无 无 虚拟机栈 线程私有,生命周期与线程相同,使 ...

  7. 深入理解 Java 虚拟机 学习笔记

    第二章 Java 内存区域与内存溢出异常 内存区域 -- from 姜志明 对象创建 加载类 若已经在内存中则跳过. 类加载完以后就可以确定对象所需的空间大小 // TODO why? 分配内存 根据 ...

  8. java outofmemory_深入理解JAVA虚拟机学习笔记3——OutOfMemoryError异常

    开门见山. 为了方便制造溢出,将JAVA堆的大小调整为10M. 本机用的是IntelliJ IDEA作为开发工具,进入到IDEA的安装目录,如D:\tools\IntelliJ IDEA 2017.1 ...

  9. 深入理解JAVA虚拟机学习笔记11——JDK可视化工具-VisualVM以及案例分析

    VisualVM:多合一故障处理工具,功能比较全面的一个工具,与其它的检测工具相比,对实际性能影响很小,并且还具备安装插件功能.这个工具和前面介绍的JConsole工具有很多类似的功能,但是比JCon ...

  10. [JVM] java虚拟机内存管理机制及垃圾收集

    Table of Contents 虚拟机内存结构详解 程序计数器 虚拟机栈 JVM stack 本地方法栈 native method stack 常量池 堆 heap 方法区 method are ...

最新文章

  1. [armv9]-Introducing-Arm-Confidential-Compute-Architecture
  2. 最小公倍数 最大公约数
  3. Docker实践:Centos下安装Docker并简单的使用
  4. 牛客 - Subset of Five(背包)
  5. Antd 修改主题颜色2018 最新版 填坑记录
  6. Linux实战教学笔记52:GlusterFS分布式存储系统
  7. 修改Tomcat编码方式的两种方法
  8. 滤镜怎么调_手机、电脑怎么剪辑视频?真心求推荐实用工具
  9. LwIP之数据包管理
  10. 如何在网上获取国际、国内的学术会议消息
  11. 02 - 用wxStreamToTextRedirector和wxTextCtrl输出std::cout
  12. 网络管理与维护作业11
  13. UVA474 Heads / Tails Probability【数学】
  14. 【剑指 offer】—— 快速排序
  15. wps 函数android,安卓版WPS教程:用ABS函数计算营收差额
  16. 微信小程序报 47001 - data format error hint
  17. 数格子算面积的方法_数方格在平面图形面积公式推导教学中的妙用
  18. htc xv6950 刷机方法
  19. 机器学习模型评估方法
  20. 博客园博客排版(js样式实例)

热门文章

  1. 伊隆马斯克提供了更多关于特斯拉骑乘网络的细节
  2. 游戏音乐从红白机到音乐会的发展历程
  3. VLAN应用篇系列:(8)Cisco交换机 PVLAN技术应用(高级的隔离技术)
  4. CCNP SWITCH gns3 简单模拟Pvlan实验
  5. 免费!终极ChatGPT提示+Midjourney宝藏神图,1200+图片,震撼人心
  6. python切割图片
  7. 双作业操作,双任务,双侧任务,这三个范式的区别是什么?|小白心理-312/347考研答疑
  8. 基于MATLAB开发AUTOSAR软件应用层模块-part17.AUTOSAR Dictionary编辑AUTOSAR元素-CS interface
  9. 个人Github贡献汇总
  10. java rtmp服务器_RTMP服务器安装