hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

这一次,终究体系的进修了 JVM 内存构造

2019-11-18杂谈搜奇网37°c
A+ A-

近来在看《 JAVA并发编程实践 》这本书,内里触及到了 Java 内存模子,经由历程 Java 内存模子水到渠成的来到的 JVM 内存组织,关于 JVM 内存组织的认知还停留在上大学那会的课堂上,一向没有体系的进修这一块的学问,所以这一次我把《 深切明白Java虚拟机JVM高等特征与最好实践 》、《 Java虚拟机范例 Java SE 8版 》这两本书中关于 JVM 内存组织的部份都看了一遍,算是对 JVM 内存组织有了新的熟悉。JVM 内存组织是指:Java 虚拟机定义了多少种顺序运转时期会运用的运转时数据区,个中有一些会跟着虚拟机启动而建立,跟着虚拟机退出而烧毁,另一些则与线程一一对应,跟着线程的最先而建立,跟着线程的完毕而烧毁。细致的运转时数据区如下图所示:

在 Java 虚拟机范例中,定义了五种运转时数据区,离别是 Java 堆、要领区、虚拟机栈、当地要领区、顺序计数器,个中 Java 堆和要领区是线程同享的。接下来就细致看看这 五种运转时数据区。

Java 堆(Heap)

Java 堆是一切线程同享的一块内存地区,它在虚拟机启动时 就会被建立,而且单个 JVM 历程有且唯一一个 Java 堆。Java 堆是用来寄存对象实例及数组,也就是说我们代码中经由历程 new 关键字 new 出来的对象都寄存在这里。所以这里也就成为了垃圾接纳器的重要运动营地了,因而它就有了一个别号叫做 GC 堆,依据垃圾接纳器的划定规矩,我们可以对 Java 堆举行进一步的离别,细致 Java 堆内存组织如下图所示:

我们可以将 Java 堆离别为新生代和老年代两个大模块,在新生代中,我们又可以进一步分为 Eden 空间、From Survivor 空间(s0)、To Survivor 空间(s1),Survivor 空间有一个为空,用于发作 GC 时寄存存活对象,老年代寄存的是经由屡次 Minor GC 依然存活的对象或许是一些大对象,FGC 就是发作在老年代。

上面就是 Java 堆的细致组织,我们也晓得 Java 堆中的各空间大小,我们是可以动态掌握的,这个在图中我也举行了简朴的标注,下面我们一同来细致的相识一下这三个参数:

  • -Xms:JVM启动时要求的初始Heap值,默以为操作体系物理内存的1/64,比方-Xms20m
  • -Xmx:JVM可要求的最大Heap值,默许值为物理内存的1/4,比方-Xmx20m,我们最好将 -Xms 和 -Xmx 设为雷同值,防止每次垃圾接纳完成后JVM重新分派内存;
  • -Xmn:设置新生代的内存大小,-Xmn 是将NewSize与MaxNewSize设为一致,我们也可以离别设置这两个参数

在 Java 堆中会发作 OOM 异常,当我们的 Java 堆内有充足的空间去完成实例分派时,而且堆也没法扩大,将会抛出我们罕见的OutOfMemoryError 异常,如下图所示:

关于 OOM 异常,我照样想多说一句,网上有一道异常火的面试题:JVM 堆内存溢出后,其他线程是不是可继承事情?,我个人以为不少回覆是毛病的,有兴致的可以研究一下。

要领区(Method Area)

要领区(Method Area)与 Java 堆一样,是各个线程同享的内存地区,是 Java 虚拟机中唯二的内存同享地区。在 Java 虚拟机范例中是如许定义要领区的:它存储了每一个类的组织信息,比方运转时常量池、字段、要领数据、组织函数和一般要领的字节码内容,还包含一些在类、实例、接口初始化时用到的特别要领。

要领区在虚拟机启动的时刻被建立,虽然要领区是堆的逻辑组成部份,然则简朴的虚拟机完成可以挑选在这个地区不完成垃圾网络与紧缩,要领区在现实内存空间中可以不是一连的,关于要领区的容量,你可以是牢固的,也可以跟着顺序的实行动态扩大,而且在不须要过量空间时自动压缩。

上面都是 Java 虚拟机中的范例,来看看细致的完成,拿我们经常使用的 HotSpot 虚拟机来讲,在 JDK1.8 之前,要领区也被称作为永远代,这个要领区会发作我们罕见的 java.lang.OutOfMemoryError: PermGen space 异常,我们也可以经由历程启动参数来掌握要领区的大小:

  • -XX:PermSize 设置最小空间
  • -XX:MaxPermSize 设置最大空间

在 JDK1.8 今后,HotSpot 虚拟机对要领区举行了不小的修改,完整移除了永远代,将本来寄存在永远代的数据迁移至 Java 堆 或许 Metaspace,要领区被移至到了 Metaspace,字符串常量移至 Java Heap,换句话说就是 JDK1.8 最先,Metaspace 也就是我们所谓的要领区,为何要做这个转变呢?也许是基于以下两点缘由:

  • 由于 PermGen 内存经常会溢出,激发恼人的 java.lang.OutOfMemoryError: PermGen,因而 JVM 的开发者愿望这一块内存可以更天真地被治理,不要再经常出现如许的 OOM
  • 移除 PermGen 可以增进 HotSpot JVM 与 JRockit VM 的融会,由于 JRockit 没有永远代。

我们也可以经由历程设置参数来掌握 Metaspace 的空间大小,重要有以下几个敕令:

  • -XX:MetaspaceSize :分派给类元数据空间(以字节计)的初始大小。MetaspaceSize的值设置的过大会延伸垃圾接纳时候。垃圾接纳事后,引发下一次垃圾接纳的类元数据空间的大小可以会变大。
  • -XX:MaxMetaspaceSize: 分派给类元数据空间的最大值,凌驾此值就会触发Full GC,此值默许没有限定,但应取决于体系内存的大小。JVM会动态地转变此值。
  • -XX:MinMetaspaceFreeRatio:示意一次GC今后,为了防止增加元数据空间的大小,余暇的类元数据的容量的最小比例,不够就会致使垃圾接纳。
  • -XX:MaxMetaspaceFreeRatio:示意一次GC今后,为了防止增加元数据空间的大小,余暇的类元数据的容量的最大比例,不够就会致使垃圾接纳。

Java 虚拟机栈(JVM Stacks)

每一条 Java 虚拟机线程都有自身私有的 Java 虚拟机栈,这个 Java 虚拟机栈跟线程同时建立,所以它跟线程有雷同的生命周期。Java 虚拟机栈形貌的是 Java 要领实行的内存模子:每一个要领在实行的同时都邑建立一个栈帧,用于存储局部变量表、操作数栈、动态链接、要领出口等信息,每一个要领从挪用直至实行完成的历程,就对应着一个栈帧在 Java 虚拟机栈中的入栈到出栈的历程

局部变量表寄存了编译期可知的种种基本数据范例(boolean、byte、char、short、int、float、long、double)、对象援用(reference 范例,它不等同于对象自身,依据差别的虚拟机完成,它多是一个指向对象肇端地点的援用指针,也可以指向一个代表对象的句柄或许其他与此对象相干的位置)和 returnAddress 范例(指向了一条字节码指令的地点)。

个中 64 位长度的 long 和 double 范例的数据会占用 2 个局部变量空间(Slot),其他的数据范例只占用 1 个。局部变量表所需的内存空间在编译时期完成分派,当进入一个要领时,这个要领须要在帧中分派多大的局部变量空间是完整肯定的,在要领运转时期不会转变局部变量表的大小。

Java 虚拟机栈既许可被完成成牢固的大小,也许可依据盘算动态来扩大和压缩,假如采纳牢固大小的话,每一个线程的 Java 虚拟机栈容量可以在线程建立的时刻自力选定。在 Java 虚拟机栈中会发作两种异常,这个在虚拟机范例中有指出:

  • 假如线程要求分派的栈容量凌驾 Java 虚拟机栈许可的最大容量,Java 虚拟机将会抛出 StackOverflowError 异常;
  • 假如 Java 虚拟机栈可以动态扩大,而且在尝试扩大的时刻没法要求到充足的内存或许在建立新的线程时没有充足的内存去建立对应的 Java 虚拟机栈,那末虚拟机将会抛出 OutOfMemoryError 异常。

顺序计数器(Program Counter Register)

顺序计数器也是线程私有的,它只须要一块较小的内存空间,你可以把它看做当前线程所实行的字节码的行号指示器,在虚拟机的概念模子里(仅是概念模子,种种虚拟机可以会经由历程一些更高效的体式格局去完成),字节码诠释器事情时就是经由历程转变这个计数器的值来拔取下一条须要实行的字节码指令,分支、轮回、跳转、异常处置惩罚、线程恢复等基本功用都须要依靠这个计数器来完成。

我们晓得在多线程的状况下,并非一条线程一向实行完,而是多个线程轮番切换实行,所以为了线程切换后可以恢复到准确的实行位置,我们就须要顺序计数器来通知线程接下来该实行哪条指令。假如线程正在实行的是一个Java 要领,这个计数器纪录的是正在实行的虚拟机字节码指令的地点,假如正在实行的是 Natvie 要领,这个计数器值则为空(Undefined)。

须要特别注意的是,顺序计数器是唯一一个在Java虚拟机范例中没有划定任何 OutOfMemoryError 状况的地区

当地要领栈(Native Method Stacks)

当地要领栈(Native Method Stacks)与 Java 虚拟机栈所发挥的作用是异常类似的,其区分不过是 Java 虚拟机栈为虚拟机实行 Java 要领(也就是字节码)效劳,而当地要领栈则是为虚拟机运用到的 Native 要领效劳。虚拟机范例中对当地要领栈中的要领运用的言语、运用体式格局与数据组织并没有强迫划定,因而细致的虚拟机可以自在完成它。以至有的虚拟机(比如Sun HotSpot虚拟机)直接就把当地要领栈和虚拟机栈合二为一。

与 Java 虚拟机栈一样,当地要领栈地区也会抛出 StackOverflowError 和 OutOfMemoryError 异常。

参考

  • 《 深切明白Java虚拟机JVM高等特征与最好实践 》
  • 《 Java虚拟机范例 Java SE 8版 》

末了

现在互联网上许多大佬都有 JVM 内存组织相干文章,如有雷同,请多多见谅了。原创不容易,码字不容易,还愿望人人多多支撑。若文中有所毛病的地方,还望提出,感谢,迎接扫码关注微信民众号:「平头哥的手艺博文」,和平头哥一同进修,一同提高。

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
这一次,终究体系的进修了 JVM 内存构造

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282311.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>