java虚拟机内存模型
线程私有区:线程私有,随线程创建而创建
-
虚拟机栈:
栈里面是一个个栈帧,每个栈帧对应一次方法调用。
栈帧中存放了局部变量表(基本数据类型标量和对象引用),操作数栈,方法出口等信息。
当前栈帧:
局部变量表:局部变量表一组变量值存储空间,用于存放方法参数和方法内不定义的局部变量
操作数栈:也称为操作栈,是后入先出栈。会有各种字节码指令往操作数栈中写入和提取内容,就是出栈/入栈操作。
动态链接:class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数。
方法返回地址:正常退出,异常退出,在方法退出后都需要返回到方法被调用的位置,程序才能继续执行。而虚拟机栈中的“返回地址”就是用来帮助当前方法恢复他的上层方法执行状态。
当栈调用深度大于jvm所允许的范围,会抛出StackOverFlowError栈溢出的错误。
- 本地方法栈:
主要与Native方法相关
- 程序计数器:
也叫pc寄存器,JVM支持多个线程同时运行,每个线程都有自己的程序计数器。
如当前执行的是JVM的方法,则该寄存器中保存当前执行指令的地址;
若当前执行的是native方法,则pc寄存器中为空
ps:线程执行过程中并不都是一次性执行完,有可能在一个cpu时钟周期内没有执行完,由于时间片用完了,所以不得不暂停执行,当下一次获得cpu资源时,通过程序计数器就知道应该从什么地方开始执行
线程共享区
- 方法区:
方法区存放类的信息(包括类的字节码,类的结构),常量,静态变量等。
字符串常量池就是在方法区中。很多人将方法区成为永久刀(Permanent Generation)
- 堆区:
堆中存放的是数组(ps:数组也是对象)和对象,当申请不到空间是会抛出OutOfMemoryError(堆溢出)
永久代
是方法区的一种实现,并且只有HotSpot中才有永久代(PermGen space),而对于其他类型的虚拟机并没有永久代(PermGen space)
在JDK1.8中,HotSpot已经没有永久代(PermGen space)这个区间了,取而代之的是元空间(Metaspace)
在JDK1.8中,永久代已经不存在,存储的类信息,编译后的代码数据已经移动到了元空间(MetaSpace)中,
元空间并没有处于堆内存上,二十直接占用的本地内存(NativeMemory)
元空间的本质和永久代类似,都是对JVM规范中方法区的实现
不过元空间与永久代之间最大的区别在于:
元空间并不存在虚拟机中,二十使用本地内存
元空间的大小仅受本地内存限制,可以通过以下参数来指定元空间的大小:
- -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值
- -XX:MaxMetaspaceSize,最大空间,默认是没有限制的
- -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
- -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
堆内存划分
1.7以及其前期版本中,堆内存区域划分为:
年轻代(yong Generation):Eden,Survior1,survior2
老年代(Old Generation):
永久代(Permanent Generation)
1.8中把存放元数据中的永久内存从堆内存中移到了本地内存中
年轻代(yong Generation):Eden,Survior1,survior2
老年代(Old Generation):
元空间(Metaspace VM Metadata in native memory):直接在本地内存中,不在堆内存中
网友评论