JVM部分数据整理

一、运行时数据区域

Java运行时内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区域【Java堆、方法区】、直接内存(不受JVM GC管理)

1、线程私有部分

1.1、程序计数器

程序计数器(Program Counter Register)一块较小的内存空间,是当前线程所执行的字节码的行号指示器。

1.2、虚拟机栈

生命周期与线程相同。Java虚拟机栈(Java Virtual Machine Stacks)是描述Java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

1.3、本地方法栈

本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,区别是虚拟机栈为执行Java方法服务,而本地方法栈则为Native方法服务。HotSpot VM将本地方法栈和虚拟机栈合二为一。

2、线程共享

2.1、堆区(Heap)

创建的对象和数组都保存在Java堆内存中,也是垃圾收集器进行垃圾收集的最重要的内存区域。现代VM基本都采用分代收集算法,所以Java堆中还可以细分为:新生代(Eden区、From Survivor区和To Survivor区)和老年代。Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。最新的垃圾收集器ZGC、Shenandoah等已经不再使用分代模型,G1收集器只是逻辑分代,物理上不分代。

2.2、方法区/永久代(元空间)

永久代(Permanent Generation)用于存储被JVM加载的类信息、常量、静态变量、JIT编译后的代码等数据, HotSpot VM把GC分代收集扩展至方法区, 即使用Java堆的永久代来实现方法区, 这样HotSpot的垃圾收集器就可以像管理Java堆一样管理这部分内存, 而不必为方法区开发专门的内存管理器(永久带的内存回收的主要目标是针对常量池的回收和类型的卸载, 因此收益一般很小);

在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所代替。区别在于:元空间并不在虚拟机中,而是使用本地内存。

2.3、运行时常量池

运行时常量池(Runtime Constant Pool)是属于方法区的一部分。Class文件中除了有类的版 本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。 Java虚拟机对Class文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会 被虚拟机认可、装载和执行。1.7版本之前,字符串常量池位于PermSpace(永久代),FGC并不会进行清理,1.8之后,字符串常量池位于堆区,会触发FGC的清理

2.4、直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域。在JDK1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

二、垃圾回收与算法

1、如何确定垃圾?

什么样的对象被称为垃圾?

没有任何引用指向的对象被称为垃圾。

1.1、引用计数法

通过引用计数(Reference Counting)来判断一个对象是否可以回收,

1.2、可达性分析

Java通过可达性分析(Reachability Analysis)来判定对象是否存活的。通过一系列的“GC Roots”对象作为起点搜索。如果一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。【ps:不可用对象(不可达对象)不等价于可回收对象,不可用对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收】

备注:可以作为GC Roots的结点?

  • 线程栈中引用的对象
  • 方法区类静态属性引用的对象
  • 方法区常量池引用的对象
  • 本地方法栈JNI(一般是所谓的Native方法)引用的对象

2、标记清除算法

“标记-清除”(Mark-Sweep)算法,算法分为“标记”和“清除”两个阶段;标记阶段标记处所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。

不足之处:

  • 效率偏低(需要扫描两遍)
  • 空间问题(位置不连续,会产生内存碎片)

3、复制算法

“复制”(Copying)算法,将内存按容量划分为大小相等的两块,每次只适用其中的一块。当这一块的内存用完了,就将还存在着的对象复制到另外一块上面,然后再把已使用过的内存空间一次性清理掉。

  • 没有碎片,但是浪费空间

4、标记整理算法

“标记-整理”(Mark-Compact)算法,标记过程与Mark-Sweep算法一样,后续步骤是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

  • 没有碎片,但是效率偏低(需要移动指针进行调整)

5、分代收集算法

“分代收集”(Generational Collection)算法,是根据对象存活周期的不同将内存划分为几块。根据各个年代的特点采用最适当的收集算法。一般在新生代中采用复制算法,老年代中采用“标记-清除”或者“标记-整理”算法进行回收;

6、垃圾收集类型

新生代的被称为Minor GC(或者Young GC);

老年代的被称为Major GC;

整体性的被称为Full GC;

在G1收集器中老年代被称为Mixed GC;

三、Java中四种引用类型

1、强引用(Strong Reference)

普遍存在于程序中,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

2、软引用(Soft Reference)

用来描述一些还有用但并非必需的对象,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。

3、弱引用(Weak Reference)

也是用来描述非必需对象的,对于弱引用的对象来说,只要垃圾收集器一运行,不管JVM的内存空间是否足够,总会回收该对象占用的内存。

4、虚引用(Phantom Reference)

被称为幽灵引用或者幻影引用,必须和引用队列联合使用,唯一目的就是能在这个对象被收集器回收时收到一个系统通知。(跟踪对象被垃圾回收的状态)

四、垃圾收集器

垃圾收集算法是内存回收的方法论,垃圾收集器是内存回收的具体实现。Java堆内存被划分为新生代和老年代两部分,新生代主要使用 Copying 和 Mark-Sweep 垃圾回收算法;老年代主要使用 Mark-Compact 垃圾回收算法。

0、垃圾收集器与内存大小的关系

  1. Serial 几十MB
  2. PS 上百兆 - 几个GB
  3. CMS - 20GB 左右
  4. G1 - 上百GB
  5. ZGC - 4T - 16T(JDK13)

1、Serial收集器

是一个单线程的收集器(新生代采用 Copying 算法,老年代采用 Mark-Compact 算法),在进行垃圾回收的时候,必须暂停其他所有的工作线程,直到它收集结束。这项工作由虚拟机在后台自动发起和自动完成。

2、ParNew 垃圾收集器

是 Serial 收集器的多线程版本,除了使用多线程进行垃圾收集室外,其余的行为和Serial 收集器完全一样。

3、Parallel Scavenge 收集器

属于新生代收集器,也使用复制算法,同样是使用多线程,他的关注点是程序达到一个可控制的吞吐量(Throughput),被称为“吞吐量优先”的收集器。

4、Serial Old 收集器

是Serial收集器的老年代版本,同样是单线程收集器,使用“Mark-Compact”算法。

5、Parallel Old 收集器

是 Parallel Scavenge 收集器的老年代版本,使用多线程和“Mark-Compact”算法。

6、CMS 收集器

Concurrent mark sweep(CMS)收集器是一种以获取最短回收停顿时间为目标的收集器,基于“Mark-sweep”算法,

分为以下四个步骤:

  • 初始标记:只是标记以下 GC Roots 能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。

  • 并发标记:进行 GC Roots 跟踪的过程,和用户线程一起工作,不需要暂停工作线程。

  • 重新标记:修正在并发标记期间因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录,需要进行STW。

  • 并发清除:清除 GC Roots 不可达对象,和用户线程一起工作,不需要暂停工作线程。

7、G1收集器

G1收集器是一款面向服务端应用的垃圾收集器

具备的特点:

  • 并行与并发
  • 分代收集
  • 空间整合
  • 可预测的停顿

使用G1收集器时,Java堆的内存布局就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region)

G1收集器的运作大致流程:

  • 初始标记
  • 并发标记
  • 最终标记
  • 筛选回收

8、Shenandoah收集器

Shenandoah使用转发指针和读屏障来实现并发整理。

  • 初始标记
  • 并发标记
  • 最终标记
  • 并发清理
  • 并发回收
  • 初始引用更新
  • 并发引用更新
  • 最终引用更新
  • 并发清理

9、ZGC收集器

ZGC收集器是一款基于Region内存布局的,(暂时)不设分代的,使用了读屏障、染色指针和内存多重映射等技术来实现可并发的标记-整理算法的,以低延迟为首要目标的一款垃圾收集器。

ZGC收集器主要使用染色指针技术来实现。

  • 小型Region:容量固定为 2MB,用于放置小于 256KB 的小对象。

  • 中型Region:容量固定为 32MB,用于放置大于登录 256kb 但小于4MB 的对象。

  • 大型Region:容量不固定,可以动态变化,但必须为2MB的整数倍,用于存放4MB以上的大对象。

  • 并发标记

  • 并发预备重分配

  • 并发重分配

  • 并发重映射

五、JVM调优思路

调优是针对特定场景、特定目的的事情,对于GC调优来说,首先就需要清楚调优的目标是什么?从性能的角度看,通常关注三个方面,内存占用(footprint)、延时 (latency)和吞吐量(throughput),大多数情况下调优会侧重于其中一个或者两个方面的目标,很少有情况可以兼顾三个不同的角度。当然,除了上面通常的三个方面,也可能需要考虑其他GC相关的场景,例如,OOM也可能与不合理的GC相关参数有关;或者,应用启动速度方面的需求,GC也会是个考虑的方面。

什么是调优?

  1. 根据需求进行 JVM 规划和预调优
  2. 优化运行 JVM 运行环境(慢,卡顿)
  3. 解决 JVM 运行过程中出现的各种问题(OOM等)

基本调优思路为

  • 理解应用需求和问题,确定调优目标。
  • 掌握JVM和GC的状态,定位具体的问题,确定真的有GC调优的必要。
  • 选择的GC类型是否符合我们的应用特征,如果是,具体问题表现在哪里,是Minor GC过长,还是Mixed GC等出现异常停顿情况;如果不是,考虑切换到什么类 型,如CMS和G1都是更侧重于低延迟的GC选项。
  • 通过分析确定具体调整的参数或者软硬件配置。
  • 验证是否达到调优目标,如果达到目标,即可以考虑结束调优;否则,重复完成分析、调整、验证这个过程。

JVM参数调优

  • 堆初始值和堆内存最大值保持一致,减少垃圾回收机制次数。
  • 设置新生代与老年代回收比例(新生代与老年代1/3或1/4)

六、GC常用参数

GC常用参数

  • -Xmn -Xms -Xmx -Xss

    年轻代 最小堆 最大堆 栈空间
  • -XX:+UseTLAB

    使用TLAB,默认打开
  • -XX:+PrintTLAB

    打印TLAB的使用情况
  • -XX:TLABSize

    设置TLAB大小
  • -XX:+DisableExplictGC

    System.gc()不管用 ,FGC
  • -XX:+PrintGC
  • -XX:+PrintGCDetails
  • -XX:+PrintHeapAtGC
  • -XX:+PrintGCTimeStamps
  • -XX:+PrintGCApplicationConcurrentTime (低)

    打印应用程序时间
  • -XX:+PrintGCApplicationStoppedTime (低)

    打印暂停时长
  • -XX:+PrintReferenceGC (重要性低)

    记录回收了多少种不同引用类型的引用
  • -verbose:class

    类加载详细过程
  • -XX:+PrintVMOptions
  • -XX:+PrintFlagsFinal -XX:+PrintFlagsInitial

    必须会用
  • -Xloggc:opt/log/gc.log
  • -XX:MaxTenuringThreshold

    升代年龄,最大值15
  • 锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 ...

    这些不建议设置

Parallel常用参数

  • -XX:SurvivorRatio
  • -XX:PreTenureSizeThreshold

    大对象到底多大
  • -XX:MaxTenuringThreshold
  • -XX:+ParallelGCThreads

    并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
  • -XX:+UseAdaptiveSizePolicy

    自动选择各区大小比例

CMS常用参数

  • -XX:+UseConcMarkSweepGC
  • -XX:ParallelCMSThreads

    CMS线程数量
  • -XX:CMSInitiatingOccupancyFraction

    使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)
  • -XX:+UseCMSCompactAtFullCollection

    在FGC时进行压缩
  • -XX:CMSFullGCsBeforeCompaction

    多少次FGC之后进行压缩
  • -XX:+CMSClassUnloadingEnabled
  • -XX:CMSInitiatingPermOccupancyFraction

    达到什么比例时进行Perm回收
  • GCTimeRatio

    设置GC时间占用程序运行时间的百分比
  • -XX:MaxGCPauseMillis

    停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代

G1常用参数

  • -XX:+UseG1GC
  • -XX:MaxGCPauseMillis

    建议值,G1会尝试调整Young区的块数来达到这个值
  • -XX:GCPauseIntervalMillis

    ?GC的间隔时间
  • -XX:+G1HeapRegionSize

    分区大小,建议逐渐增大该值,1 2 4 8 16 32。

    随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长

    ZGC做了改进(动态区块大小)
  • G1NewSizePercent

    新生代最小比例,默认为5%
  • G1MaxNewSizePercent

    新生代最大比例,默认为60%
  • GCTimeRatio

    GC时间建议比例,G1会根据这个值调整堆空间
  • ConcGCThreads

    线程数量
  • InitiatingHeapOccupancyPercent

    启动G1的堆空间占用比例

002-JVM部分的更多相关文章

  1. jvm学习002 虚拟机类加载过程以及主动引用和被动引用

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

  2. 问题002:我们要使用的Java是哪个版本的?什么是JVM、JRE、JDK、IDE、API?

    三个版本:1.java SE 标准版 2.java EE企业版 3.Java ME 小型版本 JVM (java virtual machine) java虚拟机 JRE(java runtime e ...

  3. JVM参数(二)参数分类和即时(JIT)编译器诊断

    在这个系列的第二部分,我来介绍一下HotSpot JVM提供的不同类别的参数.我同样会讨论一些关于JIT编译器诊断的有趣参数. JVM 参数分类 HotSpot JVM 提供了三类参数.第一类包括了标 ...

  4. JVM垃圾回收(二)- Minor GC vs Major GC vs Full GC

    Minor GC vs Major GC vs Full GC 垃圾回收的活动会清理对内存中的不同区域,这些事件一般被称为Minor,Major以及Full GC events.本章我们会讨论这些清理 ...

  5. JVM笔记10-性能优化之高级特性

    一.垃圾回收器配置和 GC 日志分析 1.堆典型配置: 32位的操作系统限制堆大小介于1.5G到2G,64位操作系统无限制,同时系统可用虚拟内存和可用物理内存都会限制最大堆的配置. 堆空间分配典型配置 ...

  6. JVM参数MetaspaceSize的误解

    前言 昨天谢照东大神在群里提出一个问题:怎么查看Metaspace里具体包含的是什么,起因是他的某个服务设置了-XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=5 ...

  7. JVM实用参数(二)参数分类和即时(JIT)编译器诊断

    JVM实用参数(二)参数分类和即时(JIT)编译器诊断 作者: PATRICK PESCHLOW     原文地址    译者:赵峰 校对:许巧辉 在这个系列的第二部分,我来介绍一下HotSpot J ...

  8. JVM的GC简介和实例

    本文是一次内部分享中总结了jvm gc的分类和一些实例, 内容是introduction级别的,供初学人士参考.成文仓促,难免有些错误,如果有大牛发现,请留言,我一定及时更正,谢谢!JVM内存布局主要 ...

  9. JVM体系结构详解

    每个Java开发人员都知道字节码将由JRE (Java运行时环境)执行.但是很多人不知道JRE是Java Virtual Machine(JVM)的实现,它分析字节码.解释代码并执行代码.作为开发者, ...

  10. java架构之路-(面试篇)JVM虚拟机面试大全

    下文连接比较多啊,都是我过整理的博客,很多答案都在博客里有详细说明,理解记忆是最扎实的记忆.而且我的答案不一定是最准确的,但是我的答案不会让你失望,而且几乎每个答案都是问题的扩展答案. 1.JVM内存 ...

随机推荐

  1. Oracle数据库故障处理方法

    1.启动数据库报错:ORA-01102:cannot mount database in EXCLUSIVE mode 给客户处理oracle故障,遇到如下报错: 以sys登录至数据库,执行shutd ...

  2. 数字千万别用puts!

    为了图省事我好几次都习惯的用puts输出一些确定答案,比如直接puts("-1"); 每次都wa到心态崩溃才想起来数字不能用puts...

  3. C++中main函数的返回值一定要是int

    因为大学上课时候,经常是在主函数中做处理,直接用cout语句输出到显示设备,所以一直在用void main(). 直到后面具体编程的时候,才发现void main()这种用法是按 C89(C语言的早期 ...

  4. vue 在有大数据量的 table 中使用弹窗 input 输入数据时卡顿解决方案

    vue 在有大数据量的 table 中使用弹窗 input 输入数据时卡顿解决方案 原因:vue在进行输入时,进行了多次的render刷新渲染操作,导致了input框输入时发生的卡顿现象 解决方法:在 ...

  5. Web 开发之 HTTP/2 & SPDY & HTTP 1.1 & HTTP 对比分析详解!

    1 https://zh.wikipedia.org/wiki/HTTP/2 HTTP/2 维基百科,自由的百科全书                         HTTP/2(超文本传输协议第2版 ...

  6. web 存储方式汇总:Cookies,Session, Web SQL; Web Storage(LocalStorage ,SessionStorage),IndexedDB,Application Cache,Cache Storage

    1 1 1 web 存储方式汇总: 旧的方式: Cookies; Session; Web SQL; 新的方式 HTML5 : Web Storage(LocalStorage ,SessionSto ...

  7. Node.js Backend Developer

    Node.js Backend Developer refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  8. convert URL Query String to Object All In One

    convert URL Query String to Object All In One URL / query string / paramas query string to object le ...

  9. what's the print number means after called the setTimeout function in Chrome console?

    what's the print number means after called the setTimeout function in Chrome console? javascript fun ...

  10. css & object-fit & background-image

    css & object-fit & background-image object-fit /*default fill */ object-fit: fill|contain|co ...