作为一名java程序猿,大家在寻找新的工作机会参加企业面试时,或多或少会被面试官嘚到Java底层相关的一些问题。比如和java语言相关的JVM内存模型,类加载机制,GC回收机制等等。这些问题在现如今的面试中,已经屡见不鲜。所以博主为这些相关的常见面试问题,做出了一份总结,下面为大家带来JVM内存模型的总结。
首先大家要知道的是 JVM内存模型划分5个模块:
(1)堆 Heap
(2)方法区 Method Area
(3)虚拟机栈 VM Stacks
(4)本地方法栈 Native Method Stack
(5)程序计数器 PC寄存器 Program Counter Register
接下来为大家针对每一个模型展开具体说明:
一、堆 Head
堆 区域主要是负责Java对象的存储,在Java语言中几乎是任何通过 new 关键字创建的对象实例或者数组等都被分配到堆中,为对象分配一份内存空间。同时堆区域也是jvm虚拟机中占据内存空间最大的一块,该内存区域也是被所所有线程共享的。
在该区域内,如果没有内存完成实例对象内存空间的分配,将会抛出OutOfMemoryError异常。
对于堆区域的内存空间大小,我们可以通过-Xms -Xmx 来进行调整
注意:从JDK1.7版本之后,运行时常量池从方法区移到了堆上
参数说明
-Xmx
Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定;
此设置控制 Java 堆的最大大小。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量;
用法:-Xmx512m
将最大堆大小设置为 512 兆字节
缺省值:512M
建议值:随工作负载的不同而有所变化,但高于缺省值。
-Xms
Java Heap初始值,服务端的jvm最好将-Xms和-Xmx设为相同值,开发测试服务器JVM可以保留使用默认值
此设置控制 Java 堆的初始大小。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量;
用法: -Xms256m
将初始堆大小设置为 256 兆字节
缺省值:256M
建议值:随工作负载的不同而有所变化,但高于缺省值。
-Xmn Java Heap Young 区大小,不熟悉最好保留默认值;
-Xss 每个线程的Stack大小,不熟悉最好保留默认值;
二、方法区 Method Area
它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,方法区在JDK1.7版本及以前被称为永久代,从JDK1.8永久代被移除。方法区在JDK1.8之后把名字改成了“Metaspace",可以翻译成"元数据空间"。
Java虚拟机规范将方法区描述为堆的一个逻辑部分,但它有一个别名”Non-Heap 非堆“ 用于与Java堆区分。
方法区存在的问题:
永久代容易遇到内存溢出问题(HotSpot永久代有-XX:MaxPermSize上限)
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常
运行时常量池也是方法区的一个部分,主要用于存放编译器生成的各种字面量和符号引用。类加载后会进入方法区的运行时常量池
运行时常量池存在的问题:
当常量池无法再申请到内存空间时会抛出OutOfMemoryError异常
三、虚拟机栈 VM Stacks
虚拟机栈是线程私有的内存空间,其生命周期与线程相同,是用于Java方法执行的内存模型。方法执行时会创建栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等。
虚拟机栈存在的问题:
线程请求的栈深度大于虚拟机所允许的深度时,抛出StackOverflowError异常
虚拟机栈动态扩展时无法申请到足够的内存时,抛出OutOfMemoryError异常
四、本地方法栈 Native Method Stack
与虚拟机栈发挥的作用相似,相比于虚拟机栈为Java方法服务。
本地方法栈为虚拟机使用的Native方法服务,执行每个本地方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
五、程序计数器 PC寄存器 Program Counter Register
程序计数器是线程私有的一块占用较小的内存空间,主要用于记录当前线程执行到哪里了。而且这也是唯一一个没有内存溢出的区域。
用于指示Java虚拟机下一条需要执行的字节码指令。
整体结构展示:
以上内容就是对jvm内存模型的一个总结,更多的说明偏向于对模型中每个模块的用法和作用,这里的总结没有涉及到更深层次的代码展示,感兴趣的同学,可以关注下博主的公众号,后续继续推出实际代码演示。