本章主要介绍了如何使用G1垃圾收集器以及如何将其与Hotspot JVM一起使用的基础知识。
在介绍这个技术之前先给大家简单讲一些基本简单词汇方便大家理解:
名词 | 描述 |
---|---|
JIT Compiler | just-in-time 编译器在程序启动后运行,然后将代码(通常是字节码或某种VM指令)即时(或称为即时)编译为通常更快的形式 |
CMS | 并发标记扫描 |
STW | (Stop the World ) 暂停JVM |
G1 | Garbage-First 回收器 |
Java虚拟机
我们这边众所周知 Java是一种面向对象的编程语言,
它具有平台独立性-Java应用程序被编译为字节码,该字节码存储在类文件中并加载到JVM中。java的相关应用在JVM中运行,因此它们可以在许多不同的操作系统和设备上运行。
JVM 结构
JVM的主要组件包括类加载器,运行时数据区域和执行引擎。
但是跟性能相关的组件如图:
JVM的三个组件主要在调整性能时着重。该堆是你的对象数据的存储位置。然后,该区域由启动时选择的垃圾收集器管理。大多数调整选项都与确定堆大小和实际情况选择最合适的垃圾收集器有关。JIT complier 对性能也有很大的影响。
JVM调试目标
在大型压力环境或者高并发场景的时候,通常我们调试Java 应用程序的过程中,通常会将目标放在两个点:
- System Responsiveness [响应能力]
- System Throughput[吞吐量]
[响应能力]
主要体现 三个方面:
- 用户操作浏览器请求网站返回页面的速度
- 处理事件的响应速度
- 数据库查询返回的速度
对于注重响应性的应用程序,例如 支付、登录、IM等大流量型系统 较长的STW 时间是不可接受的。需要系统在短时间内做出积极响应。
[吞吐量]
吞吐量专注于最大程度地提高应用程序在特定时间段内的工作量。如何测量吞吐量的示例包括:
- 特定时间内完成的事务数。
- 批处理程序在单位时间内可以完成的event数量。
- 单位时间内对DataBase进行查询完成数据数量集
高暂停时间对于注重吞吐量的应用程序是可以接受的。由于高吞吐量应用程序会在更长的时间内关注基准测试,因此不考虑快速响应时间。
G1垃圾收集器
垃圾优先(G1)收集器是服务器样式的垃圾收集器,目标是具有大内存的多处理器计算机。它极有可能满足垃圾回收(GC)暂停时间目标,同时实现高吞吐量。G1收集器设计用于以下应用程序 目的 是 【Oracle 官网给的结论】
我这边翻译了一下我这边理解 大概意思应该是:G1 其目的是
压缩自由的空间,减少GC引起的STW时间
增加调试的便捷性,预测更多的GC暂停时间
传统的JVM 结构(java7 与 java 8比对)
大家对比两个图发现了
二者 从java7—->java8 JVM结构是发生了变化
Oracle完全摆脱了“ PermGen【永久代】”,并用Metaspace【元空间】代替了它。
什么是PermGen?
PermGen是Permanent Generation的缩写,是Heap中的内存区域,JVM使用它来存储类和方法对象。java的应用程序加载了很多类,那么PermGen的利用率将会很高。
对于大多数应用程序,-XX:MaxPermSize=256MB 应该够了
如果大家带开发代码的过程中遇到这个错误:
“ java.lang.OutOfMemoryError:PermGen space ”
那就是这个参数导致的。
PermGen和Metaspace区别:
如图可以看出来java7 版本 PermGen是Java Heap的一部分(通过-Xmx选项配置的最大大小),到java8 的时候Metaspace不是Heap的一部分。而是元空间是本机内存(进程内存)的一部分,而本机内存仅受主机操作系统的限制,类元数据分配受可用本机内存量限制(容量将取决于否使用32位JVM与64位以及操作系统虚拟内存的可用性)。
Metaspace介绍
元空间容量
- 可以通过-xx:MaxMetaspaceSize 设置允许限制用于类元数据的本机内存量。如果不指定此标志,则Metaspace将在运行时根据应用程序需求动态调整大小。
元空间垃圾收集
- 如果类元数据使用量 达到了“ MaxMetaspaceSize”极限值,就会触发过期类和类加载器的垃圾收集。
那看到这里很多朋友会问,那其实也对程序也没有什么影响对吧?
我来解释一下,这个变化意义在哪里呢?
个人理解就是你这边在开发应用程序的时候,如果应用程序加载了高负荷类(和/或内部字符串)如果导致元工空间不足的话,可能操作系统关闭。后续对于gc系统监控有一定的便捷。
除此之外撤销的永久代,增大了Heap 堆的使用率。为新生代旧生代提供更多的空间。
CMS回收
CMS回收是在旧生代上完成.
主要步骤:
1. Initial Mark (STW)
扫描老一代集合对象中可访问的被“标记”的对象,包括那些年轻一代可能可以访问的对象。此时标记过程比较短暂 暂停时间通常持续时间较短。
2. Concurrent Marking [并发标记]
第一次标记完成,此时恢复当前暂停运行的线程,并发对第一次已经标记的对象进行循环深度标记[标记已经标记的对象可访问的对象] 需要注意 并发标记同时可能会出现Minor GC [新生代GC]同时发生,那么对应旧生代引用关系会重新改变。同时就就产生浮动垃圾【原本被引用的数据因为其他对象引用状态改变,导致不在引用】
3. Final Marking (remark)[再次标记 STW]
重新扫描,会暂停运行线程,针对Concurrent Marking 步骤过程出现的对象的更新而导致并发标记阶段遗漏的对象( 关系修改的对象以及新创建对象)进行重新标记 。
4. Concurrent Sweep [并发收集]
恢复线程,针对标记阶段被标识为不可访问的对象进行回收。死对象的集合将对象的空间添加到空闲列表中,以供以后分配。
5. Resetting 重置
通过清除数据结构为下一个并发收集做准备。
CMS Collector
年轻代 : Eden + 2个生存区
年老代: 连续的内存空间
Young GC流程
运行一段时间后 大概堆的情况是这个样子
图是按顺序执行的
Old GC流程
CMS收集器将进入重置阶段,并等待下一次达到GC阈值。
相关资料图片参考oracle官方地址:
有兴趣小伙伴可以相互学习讨论
https://www.oracle.com/technetwork/tutorials/tutorials1876574.html
最新评论
徒弟可以A师傅,学生可以A老师,为什么外包不能A正式,我觉得很正常。异性相吸这是宇宙真理
PHP天下第一(狗头叼花)
第一个不需要关注公主号直接给激活码的帖子!
客户端超时断开后,服务端如果没有设置超时机制,那也会继续等待处理,万一这期间有消息到了,那不是就接受到消息处理了,但是也没有办法返回到客户端,导致消息丢失。
企业级GO项目开发实战 Kubernetes权威指南 第六版
https://pan.baidu.com/s/1q3bnTncIACKoTZFxvx7BQw?pwd=ii7n
RabbitMQ精讲,项目驱动落地,分布式事务拔高 有吗?
Spring Cloud Alibaba 微服务架构实战 https://pan.baidu.com/s/1jF5voFRoeF0lYAzAPBWSbw?pwd=chqk