写点什么

架构师系列 10: JAVA 虚拟机的原理

用户头像
桃花原记
关注
发布于: 2020 年 12 月 20 日

简介

JVM 是 Java Virtual Machine 的缩写,它直接和操作系统进行交互,屏蔽操作系统接口的区别,所以 java 能跨平台开发就是这个原因。


JAVA 程序加载和运行



  1. Java 文件经过编译后变成 .class 字节码文件

  2. 字节码文件通过类加载器被搬运到 JVM 虚拟机中

  3. 虚拟机主要的 5 大块:方法区,堆都为线程共享区域,有线程安全问题,栈和本地方法栈和计数器都是独享区域,不存在线程安全问题,而 JVM 的调优主要就是围绕堆,栈两大块进行

① 类加载器

如果 JVM 想要执行这个 .class 文件,我们需要将其装进一个 类加载器 中,它就像一个搬运工一样,会把所有的 .class 文件全部搬进 JVM 里面来。

② 方法区

方法区 是用于存放类似于元数据信息方面的数据的,比如类信息,常量,静态变量,编译后代码···等

类加载器将 .class 文件搬过来就是先丢到这一块上

③ 堆

 主要放了一些存储的数据,比如对象实例,数组···等,它和方法区都同属于 线程共享区域 。也就是说它们都是 线程不安全 的

④ 栈

 这是我们的代码运行空间。我们编写的每一个方法都会放到  里面运行。

我们会听说过 本地方法栈 或者 本地方法接口 这两个名词,不过我们基本不会涉及这两块的内容,它俩底层是使用 C 来进行工作的,和 Java 没有太大的关系。

⑤ 程序计数器

主要就是完成一个加载工作,类似于一个指针一样的,指向下一行我们需要执行的代码。和栈一样,都是 线程独享 的,就是说每一个线程都会有自己对应的一块区域而不会存在并发和多线程的问题。

JVM 的内存

JVM 内存结构主要有三大块:堆内存方法区。堆内存是 JVM 中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden 空间From Survivor 空间To Survivor 空间,默认情况下年轻代按照 8:1:1 的比例来分配;



调整最大堆内存和最小堆内存

-Xmx:指定 java 堆最大值(默认值是物理内存的 1/4(<1GB))

–Xms:初始 java 堆最小值(默认值是物理内存的 1/64(<1GB))

默认(MinHeapFreeRatio 参数可以调整)空余堆内存小于 40%时,JVM 就会增大堆直到-Xmx 的最大限制,默认(MaxHeapFreeRatio 参数可以调整)空余堆内存大于 70%时,JVM 会减少堆直到 -Xms 的最小限制。


简单点来说,你不停地往堆内存里面丢数据,等它剩余大小小于 40%了,JVM 就会动态申请内存空间不过会小于-Xmx,如果剩余大小大于 70%,又会动态缩小不过不会小于–Xms。


开发过程中,通常会将 -Xms 与 -Xmx 两个参数的配置相同的值,其目的是为了能够在 java 垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源。


G1 垃圾收集算法


G1 收集器


G1 是目前技术发展的最前沿成果之一,HotSpot 开发团队赋予它的使命是未来可以替换掉 JDK1.5 中发布的 CMS 收集器。与 CMS 收集器相比 G1 收集器有以下特点:

  1. 空间整合,G1 收集器采用标记整理算法,不会产生内存空间碎片。分配大对象时不会因为无法找到连续空间而提前触发下一次 GC。

  2. 可预测停顿,这是 G1 的另一大优势,降低停顿时间是 G1 和 CMS 的共同关注点,但 G1 除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为 N 毫秒的时间片段内,消耗在垃圾收集上的时间不得超过 N 毫秒,这几乎已经是实时 Java(RTSJ)的垃圾收集器的特征了。


旧的垃圾收集器,收集的范围都是整个新生代或者老年代,而 G1 不再是这样。使用 G1 收集器时,Java 堆的内存布局与其他收集器有很大差别,它将整个 Java 堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔阂了,它们都是一部分(可以不连续)Region 的集合。



G1 的新生代收集跟 ParNew 类似,当新生代占用达到一定比例的时候,开始出发收集。和 CMS 类似,G1 收集器收集老年代对象会有短暂停顿。

收集步骤:

1、标记阶段,首先初始标记(Initial-Mark),这个阶段是停顿的(Stop the World Event),并且会触发一次普通 Mintor GC。对应 GC log:GC pause (young) (inital-mark)

2、Root Region Scanning,程序运行过程中会回收 survivor 区(存活到老年代),这一过程必须在 young GC 之前完成。

3、Concurrent Marking,在整个堆中进行并发标记(和应用程序并发执行),此过程可能被 young GC 中断。在并发标记阶段,若发现区域对象中的所有对象都是垃圾,那个这个区域会被立即回收(图中打 X)。同时,并发标记过程中,会计算每个区域的对象活性(区域中存活对象的比例)。



4、Remark, 再标记,会有短暂停顿(STW)。再标记阶段是用来收集 并发标记阶段 产生新的垃圾(并发阶段和应用程序一同运行);G1 中采用了比 CMS 更快的初始快照算法:snapshot-at-the-beginning (SATB)。



6、复制/清除过程后。回收区域的活性对象已经被集中回收到深蓝色和深绿色区域。



参考:

https://mp.weixin.qq.com/s?_biz=MzI4NDY5Mjc1Mg==&mid=2247483952&idx=1&sn=ea12792a9b7c67baddfaf425d8272d33&chksm=ebf6da4fdc815359869107a4acd15538b3596ba006b4005b216688b69372650dbd18c0184643&scene=21#wechatredirect

https://www.cnblogs.com/max-home/p/12270183.html


用户头像

桃花原记

关注

还未添加个人签名 2018.11.24 加入

还未添加个人简介

评论

发布
暂无评论
架构师系列 10: JAVA 虚拟机的原理