乐趣区

关于java:Jvm知识点

就算你躺在沙发上三天不起, 拉不开窗帘, 因为决定不了穿哪双袜子哭个没完, 我也不会进行爱你.
没有什么大不了的. 这个地球有 75 亿人, 就有 75 亿种失常.

前言

面试的时候 必问 JVM, 淦! 咱们筹备好好温习吧, 加油! 奇怪的常识又减少了呐.

1. JVM 内存模型

依据 JVM 标准,JVM 内存共分为虚拟机栈,堆,办法区,程序计数器,本地办法栈五个局部

程序计数器 (线程公有):
是以后线程锁执行字节码的行号治期间,每条线程都有一个独立的程序计数器,这类内存也称为“线程公有”的内存。正在执行 java 办法的话,计数器记录的是虚拟机字节码指令的地址(以后指令的地址)。如果是 Natice 办法,则为空。

java 虚拟机栈
也是 线程公有的
每个办法在执行的时候也会创立一个栈帧,存储了 局部变量,操作数,动静链接,办法返回地址
每个办法从调用到执行结束,对应一个栈帧在虚拟机栈中的入栈和出栈。
通常所说的栈,个别是指在虚拟机栈中的局部变量局部。
局部变量所需内存在编译期间实现调配,
如果线程申请的栈深度大于虚拟机所容许的深度,则 StackOverflowError。
如果虚拟机栈能够动静扩大,扩大到无奈申请足够的内存,则 OutOfMemoryError。

本地办法栈 本地办法栈(Native Method Stacks)与虚拟机栈所施展的作用是十分类似的,其
区别不过是虚拟机栈为虚拟机执行 Java 办法(也就是字节码)服务,而本地办法栈则
是为 虚拟机应用到的 Native 办法服务 。虚拟机标准中对本地办法栈中的办法应用的语
言、应用形式与数据结构并没有强制规定,因而具体的虚拟机能够自在实现它。甚至
有的虚拟机(譬如 Sun HotSpot 虚拟机)间接就把本地办法栈和虚拟机栈合二为一。
与虚拟机栈一样,本地办法栈区域也会抛出 StackOverflowError 和 OutOfMemoryError
异样

Java 堆 (线程共享)
被所有线程共享的一块内存区域,在虚拟机启动的时候创立,用于寄存对象实例。
对能够依照可扩大来实现(通过 -Xmx 和 -Xms 来管制)
当队中没有内存可调配给实例,也无奈再扩大时,则抛出 OutOfMemoryError 异样。

办法区 (线程共享)
被所有办法线程共享的一块内存区域。
用于存储曾经被虚拟机加载的类信息,常量,动态变量等。
这个区域的内存回收指标次要针对常量池的回收和堆类型的卸载。
JDK8 HotSpot JVM 将移除永恒区,应用本地内存来存储类元数据信息并称之为:元空间(Metaspace)。这意味着不会再有 java.lang.OutOfMemoryError: PermGen 问题,也不再须要你进行调优及监控内存空间的应用。

二、空间调配担保(就像贷款一样)-XX:HandlerPromotionFailure
Minor GC 之前查看
老年代最大可用间断空间是否 > 新生代所有对象总空间。
大于 —-> Minor GC
不大于—> 老年代最大可用间断空间是否 > 历次降职到老年代对象的均匀大小
大于 —–> Minor GC
不大于 —–> Full GC
-XX:HandlerPromotionFailure
注:Minor GC 是针对新生代的垃圾回收,MajorGC 是老年代的,Full GC 是 Minor GC 加上 MajorGC

堆内存划分


新生代
所有 new 的对象都在堆外面。对象优先调配到 Eden 区,能够通过参数 -XX:SurviviorRatio= 8 来指定 Eden 区和 Survivior 的比例,这样划分的根据和益处是依据 gc 的回收算法来定的。做到了内存利用率高。

通过几次(能够通过参数设置)minor gc 还存活的对象进入 S0,再通过几次 minor gc 还存活进入 S1,达到 minor gc 的阈值(-XX:MaxTenuringThreshold=?)进入老年代。

还有就是动静对象年龄断定,雷同年龄所有对象的大小总和 > survivor 空间的一半,间接升级老年代,不须要进行年龄阈值的判断。
这个区域的现实是 98% 以上的对象可能被回收。

老年代
大对象(-XX:PretenureSizeThreadshold=1024)间接进入老年代,在新生代外面长期存活的对象进入老年代。老年代对应的是 major gc。

永恒代
蕴含元数据信息,如 class,method 的 detail 信息

在 Java1.8 时, 删除了办法区, 减少了元空间, 如下图:

永恒代与元空间

PermGen 空间情况:这部分内存空间将全副移除。JVM 的参数:PermSize 和 MaxPermSize 会被疏忽并给出正告(如果在启用时设置了这两个参数)。

Metaspace 容量 默认状况下,类元数据只受可用的本地内存限度 (容量取决于是 32 位或是 64 位操作系统的可用虚拟内存大小)。 新参数(MaxMetaspaceSize)用于限度本地内存调配给类元数据的大小。如果没有指定这个参数,元空间会在运行时依据须要动静调整。

另外,对于僵死的类及类加载器的垃圾回收将在元数据应用达到“MaxMetaspaceSize”参数的设定值时进行。适时地 监控和调整元空间 对于减小垃圾回收频率和缩小延时是很有必要的。继续的元空间垃圾回收阐明,可能存在类、类加载器导致的内存透露或是大小设置不适合。

永恒代

在 JDK8 之前的 HotSpot JVM,寄存这些”永恒的”的区域叫做“永恒代 (permanent generation)”。永恒代是一片间断的堆空间,在 JVM 启动之前通过在命令行设置参数-XX:MaxPermSize 来设定永恒代最大可调配的内存空间,默认大小是 64M(64 位 JVM 因为指针收缩,默认是 85M)。永恒代的垃圾收集是和老年代(old generation) 捆绑在一起 的,因而无论谁满了,都会触发永恒代和老年代的垃圾收集。不过,一个显著的问题是,当 JVM 加载的类信息容量超过了参数 -XX:MaxPermSize 设定的值时,利用将 会报 OOM 的谬误 (对于这句话,译者的了解是:32 位的 JVM 默认 MaxPermSize 是 64M,而 JDK8 里的 Metaspace,也能够通过参数 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 设定大小,但如果不指定 MaxMetaspaceSize 的话,Metaspace 的大小仅 受限于 native memory 的残余大小。也就是说永恒代的最大空间肯定得有个指定值,而如果 MaxPermSize 指定不当,就会 OOM)。

JDK7 开始 永恒代的移除工作,储存在永恒代的一部分数据曾经转移到了 Java Heap 或者是 Native Heap。但永恒代依然存在于 JDK7,并没有齐全的移除:符号援用 (Symbols) 转移到了 native heap; 字面量 (interned strings) 转移到了 java heap; 类的动态变量 (class statics) 转移到了 java heap。

在 JDK7 update 4 即随后的版本中,提供了残缺的反对对于 Garbage-First(G1) 垃圾收集器,以取代在 JDK5 中公布的 CMS 收集器。应用 G1,PermGen 仅仅在FullGC(stop-the-word,STW) 时才会被收集。G1 仅仅在 PermGen 满了或者利用分配内存的速度比 G1 并发垃圾收集速度快的时候才触发 FullGC。

而对于 CMS 收集器,通过开启布尔参数 -XX:+CMSClassUnloadingEnabled 来并发对 PermGen 进行收集。对于 G1 没有相似的选项,G1 只能通过 FullGC,stop the world, 来对 PermGen 进行收集。

永恒代在 JDK8 中被齐全的移除了。所以永恒代的参数 -XX:PermSize 和 -XX:MaxPermSize 也被移除了。

元空间

在 JDK8 中,classe metadata(the virtual machines internal presentation of Java class), 被存储在叫做 Metaspace 的 native memory。一些新的 flags 被退出:

1、-XX:MetaspaceSize,class metadata 的初始空间配额,以 bytes 为单位,达到该值就会触发垃圾收集进行类型卸载,同时 GC 会对该值进行调整:如果开释了大量的空间,就适当的升高该值;如果开释了很少的空间,那么在不超过 MaxMetaspaceSize(如果设置了的话),适当的进步该值。

2、-XX:MaxMetaspaceSize,能够为 class metadata 调配的最大空间。默认是没有限度的。

3、-XX:MinMetaspaceFreeRatio, 在 GC 之后,最小的 Metaspace 残余空间容量的百分比,缩小为 class metadata 调配空间导致的垃圾收集

4、-XX:MaxMetaspaceFreeRatio, 在 GC 之后,最大的 Metaspace 残余空间容量的百分比,缩小为 class metadata 开释空间导致的垃圾收集

5、默认状况下,class metadata的调配仅受限于可用的 native memory 总量。能够应用 MaxMetaspaceSize 来限度可为 class metadata 调配的最大内存。当 class metadata 的应用的内存达到 MetaspaceSize(32 位 clientVM 默认 12Mbytes,32 位 ServerVM 默认是 16Mbytes)时就会对死亡的类加载器和类进行垃圾收集。设置 MetaspaceSize 为一个较高的值能够推延垃圾收集的产生。

       这里科普下,在 Windows 下称为虚拟内存(virtual memory), 在 Linux 下称为替换空间(swap space), 用于当零碎须要更多的内存资源而物理内存曾经满了的状况下,将物理内存中不沉闷的页转移到磁盘上的替换空间中。

在 JDK8,Native Memory,包含 Metaspace 和 C -Heap。

永恒代的移除对最终用户意味着什么?

因为类的元数据能够在本地内存 (native memory) 之外调配, 所以其最大可利用空间是整个零碎内存的可用空间。这样,你将不再会遇到 OOM 谬误,溢出的内存会涌入到替换空间。最终用户能够为类元数据指定最大可利用的本地内存空间,JVM 也能够减少本地内存空间来满足类元数据信息的存储。

注:永恒代的移除并不象征者类加载器泄露的问题就没有了。因而,你依然须要监控你的生产和打算,因为内存泄露会耗尽整个本地内存,导致内存替换(swapping),这样只会变得更糟。

创作不易, 如果本篇文章能帮忙到你, 请给予反对, 赠人玫瑰, 手有余香,虫虫蟹蟹观众姥爷了

退出移动版