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

深入理解
最近想好好复习一下java虚拟机,我想通过深读 【理解Java虚拟机 jvm 高级特性与最佳实践】 (作者 周志明) 并且通过写一些博客总结来将该书读薄读透,这里文章内容仅仅是个人阅读后简短总结,加强学习深度的同时方便进行知识的回顾之用。如涉及版权还望周大神看到后告知一下小弟,我会第一时间将文章下线,在此强烈推荐大家买纸质图书 【理解Java虚拟机 jvm 高级特性与最佳实践】 (作者 周志明) 进行阅读,学习java虚拟机必备。努力学习只为遇到更好的你!

第三章 垃圾收集器与内存分配策略

Java 与 C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面 的人却想出来

1 垃圾收集三个疑问

说起垃圾收集我们必须明确三件事情:
1 那些内存需要回收? 2 如何回收? 3 什么时候回收? 将这三个问题搞清楚 你就会对真正的理解垃圾收集是个什么东东?我这里将围绕这三个问题进行阐述。带着疑问去学习。

1 那些内存需要回收?

关于第二个问题和第三个问题会在后面阐述到,我们来说一下 那些内存需要进行回收。
java虚拟机的 程序计数器虚拟机栈本地方法栈
这三个内存区域 生命周期和线程一致,Sun HotSopt 直接将本地方法栈和Java 虚拟机栈 合二为一 我们这将虚拟机栈 和本地方法栈 统称为栈。而栈中存储的就是栈帧。我们的方法执行就是执行入栈和出栈的操作。在编译期每个栈帧占用内存大小已经是确定了,而程序计数器占用的内存是比较小的,所以我们不用太担心这三个内存区域的回收问题,因为一旦方法结束或线程结束内存就自然跟着回收了。
垃圾收集需要关注的是Java堆方法区,因为这2块内存区域内存非配和回收是不确定的,它们在运行期间才会知道要创建多少对象。需要转载多少类。还有就是每个对象存活的时间也各不一样。我们需要通过不同的策略区进行内存的分配和回收。

2 如何回收?

我们将不可能在被任何途径使用的对象称之为死去的对象,这些对象占用的内存就是我们进行垃圾回收的内存。那么如何判断对象已经死去呢?我们可以通过 引用计数器算法可达性分析算法 进行操作。

2.1 判断对象死去算法

2.1.1 引用计数器算法

引用计数器算法:就是给对象添加一个计数器,每当有地方引用它时,计数器加1; 当引用失效就减1。当计数器为0 就表示该对象不能在被使用。但是这种算法无法解决循环依赖的问题。
关于循环依赖具体介绍 请参考 西门吹牛 的一篇博客 https://www.cnblogs.com/gudi/p/6414420.html?utm_source=itdadao&utm_medium=referral

2.1.2 可达性分析算法

可达性分析算法 通过一系列的GCRoots 为起始点向下进行搜索 搜索的路径就是引用链,当一个对象到GCRoots没有任何一条引用链相连(也称之为GC Roots 到这个对象不可达)。那么该对象就可以被判定为回收的对象。
如图 3-1 所示,对象 object 5、object 6、object 7 虽然互相有关联,但是它们到 GC Roots 是不可达的,所以它们将会被判定为是可回收的对象。
在这里插入图片描述

java 中可作为GCRoots 的对象包括下面几种:
虚拟机栈中引用的对象方法区中类静态属性引用的对象方法区中常量池中引用的对象本地方法栈引用的对象

2.3 回收方法区

方法区又称之为HotSpot 虚拟机中的永久代,它的垃圾收集包括2部分内容:废弃常量无用的类
和java堆中对象回收类似,当一个字面常量没有被任何地方引用时 在进行垃圾收集的时候该常量内存就会被进行回收。
无用的类需要满足3个条件:

  1. 改类的所有的实例都已经被回收
  2. 加载该类的ClassLoader已经被回收
  3. 该类对应的java.lang.Class 对象没有在任何地方被引用 并且无法通过反射访问该类的方法

2.4 垃圾收集算法

标记清除算法

标记清除算法 就是先标记要回收的对象,标记完成后回收所有被标记的对象。
它的缺点有2个:
1 效率低 标记和清除的过程效率都不高。
2 会产生大量的内存碎片。
内存碎片太多会导致无法分配比较大的对象,而频繁的执行垃圾收集的操作。
在这里插入图片描述

复制算法

复制算法会将内存分为相等2块, 然后只是使用其中一块 。当使用的一块内存用完时,将存活的对象复制另一块内存中。然后在将已经使用过的内存清理掉。
这种算法优点是效率高。
缺点是要牺牲一半的内存空间。
在这里插入图片描述

在我们的java虚拟机中 新生代的对象都是朝生夕死 的,其内存并没有按照 1:1 进行划分 而是将内存分为 一个较大的Eden 和 2块较小的Survivor 默认情况下 Eden和Survivor 大小比例是 8:1

标记整理算法

标记整理算法和标记清除算法标记过程一样,区别是在进行清理的时候会将存活的对象整理到一起 然后清理掉存活对象以外的内存。
这样做的好处是减少内存碎片的产生。
在这里插入图片描述

分代收集算法

分代收集算法是根据对象存活周期的不同将内存划分为几块。这样做的好处是我们可以根据不同代的特点采用不同的垃圾收集算法。java堆分为新生代老年代
新生代: 新生代中会有大量的对象死去只有少量存活 所以采用复制算法
老年代: 对象存活率高,所以采用 标记清除标记整理算法。

2.5 HotSpot的算法实现

2.6 垃圾收器

我们上面讲了很多垃圾收集算法 而垃圾收集器就是我们这些算法的具体实现。在java虚拟机中我们通过各种垃圾收集器来完成内存的回收。
Serial 收集器
单线程作用于新生代的收集器 ,版本比较老的收集器。
ParNew 收集器
并行(多线程版)的作用于 新生代的收集器,它是Serial 收集器多线程版
Parallel Scavenge 收集器
并行的作用于新生代的收集器。 采用复制算法 可以设置吞吐量
Serial Old 收集器
单线程的作用于老年代收集器, 是Serial 收集器老年代版本收集器。
Parallel Old 收集器
并行作用于老年代收集器 ,是Parallel Scavenge 收集器的老年代版本。
CMS 收集器
并行并发的作用于新生代收集器,采用标记清除算法实现。
G1收集器
并行并发的作用于不同代的收集器,采用标记整理算法实现

3 什么时候回收

关于这个问题 书中通过内存分配和回收策略中进行详细的介绍。因为说到回收不得不说内存如何去进行分配。其实java 虚拟机就是帮我们处理了2件事情 给对象分配内存 和回收非配给对象的内存。
内存非配策略有以下几个

3.1 内存分配策略

在进行介绍之前我们要先说一下Minor GC和 Full GC 是什么? Minor GC 是新生代GC
就是发生在新生代垃圾收集操作。这个操作比较频繁回收速度也快。 Full GC/Major GC 发生在老年代的GC
一般最少执行一次Minor GC 该操作数据比较慢。一般会比Minor GC慢10倍

3.1.2 对象优先在Eden分配

大多数情况下对象在Eden区中分配,当Eden区没有足够的空间进行分配时 虚拟机将发动一次 Minor GC

3.1.2 大对象直接进入老年代

很长的字符串以及数组 我们称之为大对象,如过是大对象我们直接将其分配到老年代中。

3.1.3 长期存活的对象将进入老年代

每个对象都有一个年龄计数器 当年龄增加到一定程度后将会被晋升到老年代中。(默认是15岁)而年龄的判断是对象在Edne出生并经过一次Minor GC 后仍然存活并被Survivor 接受对象的的年龄为1 每经历一次MinorGC 年龄就增加1。

3.1.4 动态对象年龄判定

对象到达指定的年龄就进入老年代这个也不是绝对的。如果Survivor空间相同年龄对象大小总和大于Survivor空间的一半,那么年龄大于或等于该年龄的对象就可以直接进入老年代。

3.1.5 空间分配担保

在进行 Minor GC 前先判断老年代空间是否大于新生代所有对象的空间 如果大于则可以进行 MinorGC 如果不成立在检查 老年代空间是否大于晋升到老年代对象大小的空间。如果大于,如果大于就进行一次MinorGC 如果小于就进行一次Full GC。
我们的老年代就相当于新生代空间的担保人 。就想我们生活中的贷款一样,我们在贷款是一般需要有一个担保人,当你没有偿还能力是就让担保人替你偿还。我们通过这种方式来判断是否要执行Full GC

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值