生命不息,学习不止!
JVM内存模型由:堆、栈、方法区、本地方法栈、程序计数器构成了JVM运行时数据区。
JVM内存模型,如下图:
JVM内存模型
Java堆内存(Heap)
Java堆内存是JVM启动时创建的一块重要的内存区,该区域是所有线程共享的区域。Java堆内存主要的作用就是为所有的对象实例
和数组
分配内存空间,创建的对象实例和数组都被存在Java堆内存中。
Java堆内存也是JVM GC收集器管理内存区域,在Hotspot虚拟机中堆内存分为两部分新生代
和老年代
,而新生代
可划分为eden区
和survivor区
,其中Survivor区又可分为:From
和To
两个区域,Java堆内存之所以会这么划分,主要是方便堆对内存的管理。
Java 堆内存大小可以通过:``-Xms和-Xmx
来分配java堆内存的最小和最大内存,可以使用-Xmn
来调整年轻代的内存大小。
堆内存结构,如下图:
方法区(Method Area)
Java方法区是JVM线程共享的一个内存区域,Java方法区主要适用于存放,被JVM加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等信息。
在JDK8以前方法区的数据都存储在"永久代
"中,可以通过-XX:PermSize
和 -XX:MaxPermSize
指定JVM中的永久代(方法区)的大小,永久代
是在JVM中实现的,并且永久代
被占用的内存只有在FullGC的时候有可能被回收,而且回收的表现也一般。正因为这样方法区
的内存没有得到很好的管理,在使用的时候,对方法区内存控制不当会出现java.lang.OutOfMemoryError: PermGen space
,字符串量池过大、静态变量过多都会导致方法区内存空间不足。例如:我们的业务需要动态通过网络加载类信息,随着时间的延长加载类的信息逐渐变多,方法区内存得不到回收,也会出现OOM。
到了JDK8,方法区的内存通过元空间
替换掉永久代
,元空间和永久代没有太多的区别,他们的作用都是方法区的实现。元空间
和永久代
的最大区别就是,元空间不在虚拟机内存中,而是直接使用本地内存来存储方法区数据。
在默认情况下,元空间
的大小仅受本地内存限制,但可以通过:-XX:MetaspaceSize
(初始空间大小)和-XX:MaxMetaspaceSize
(最大空间)参数来指定元空间的大小,默认是不限制元空间的大小的。元空间还有两个与 GC 相关的参数:
-
-XX:MinMetaspaceFreeRatio
:在GC之后,最小的元空间
剩余空间容量的百分比 -
-XX:MaxMetaspaceFreeRatio
:在GC之后,最大的元空间
剩余空间容量的百分比
JVM栈(Java Virtual Machine Stacks)
JVM栈是JVM线程私有的内存区域,栈的生命会周期和Java线程一样。JVM栈描述的是Java方法执行的线程模型。每一个java方法被执行的时候,JVM都会同步创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等。
每一个Java方法在被调用一直到执行结束的过程,都会对应着一个栈帧
在JVM栈中的入栈
到出栈
的过程。
局部变量表
存放了编译时期可知的JVM基本数据类型(boolean、byte、char、short、int、 float、long、double
)、对象引用 和 returnAddress 类型。
这些数据类型在局部变量表
中的存储空间以局部变量槽
(Slot)来表示,其中64位长度的long
和 double
类型的数据会占用两个变量槽,其余的数据类型只占用一个。
局部变量表
所需的内存空间在编译期间完成分配
,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,方法运行期间不会改变局部变量表的大小
java虚拟机栈结构:
程序计数器(Program Counter Register)
程序计数器
是JVM线程私有的,是一块内存较小的空间。可以把程序计数器
看作是当前线程执行字节码行号的指示器
。
字节码解释器在工作的时候就是通过改变程序计数器
的值来选取下一条要执行的字节码指令。
Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现
的,在任何一 个确定的时刻,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
本地方法栈(Native M ethod Stacks)
本地方法栈
与JVM栈
非常相似,其区别是JVM栈
为虚拟机执行Java方法服务,而本地方法栈
则是为虚拟机使用到的本地方法服务.
运行时常量池(Runtime Constant Pool)
运行时常量池
是方法区的一部分。Class文件中除了有类的版本、字 段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
致此,JVM内存结构介绍结束!
生命不息,学习不止!
网友评论