Java虚拟机之内存模型

这里写图片描述

1.程序计数器

线程私有。不会内存溢出。

记录当前线程持续执行的位置(记录虚拟机字节码指令的地址)。

改变计数器的值来执行下一条指令。

2.Java虚拟机栈

线程私有。生命周期和线程一致。

描述的是java方法执行的内存模型:每个方法在执行的同时多会创建一个栈帧用于存储局部变量表、操作数栈、动态链表、方法出口等信息。

每一个方法从调用直至完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。

局部变量表存放了编译期可知的各种基本数据类型和对象引用,所需内存空间在编译期确定。

Java虚拟机栈的局部变量表存放了编译器可知的8种java基本类型数据(boolean、byte、char、short、int、float、long、double)、对象引用refrence(注意不是对象实例本身)、方法返回地址returnAddress(指向了一条字节码指令的地址)。

Java虚拟机栈的局部变量表空间单位是槽(Slot),其中64位长度的double和long类型会占用两个slot,其余的数据类型只占用一个slot。局部变量表所需内存空间在编译期间完成分配,当进入一个方法时,该方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

Java虚拟机栈有两种异常状况:如果线程请求的栈深度大于虚拟机所允许的最大深度时,抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,当扩展时无法申请到足够内存时会抛出OutOfMemoryError异常。

-Xoss参数设置本地方法栈大小(对于HotSpot无效)

-Xss参数设置栈容量 例: -Xss128k

3.本地方法栈

线程私有,与java虚拟机栈相似。

线程在调用本地方法时,来存储本地方法的局部变量表,本地方法的操作数栈等等信息。

4.堆内存

线程共享。

堆是java虚拟机所管理的内存区域中最大一块,在虚拟机启动时创建。

  • 存放对象实例,数组等信息。
  • 垃圾回收机制的主要区域。

Java堆是垃圾收集器管理的主要区域,从垃圾回收的角度看,由于现在的垃圾收集器基本都采用的是分代收集算法,因此java堆还可以初步细分为新生代和年老代。

Java虚拟机规范规定,堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。在实现上即可以是固定大小的,也可以是可动态扩展的。如果在堆中没有内存完成实例分配,并且堆大小也无法在扩展时,将会抛出OutOfMemoryError异常。

堆设置的常用参数如下:

-Xms :初始堆大小  
-Xmx :最大堆大小,当XmsXmx设置相同时,堆就无法进行自动扩展。
-XX:NewSize=n :设置年轻代大小  
-XX:NewRatio=n: 设置年轻代和年老代的比值。如:3,表示年轻代与年老代比值为13,年轻代占整个年轻代年老代和的1/4  
-XX:SurvivorRatio=n :年轻代中Eden区与Survivor区的比值。注意Survivor区有两个。
                     如:XX:SurvivorRatio=3,表示Eden区的大小是一个Survivor区的三倍,但Survivor区有两个,那么Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5。 
-XX:MaxPermSize=n :设置持久代大小  

例:VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出是dump出当前的内存堆转储快照。

5.方法区

线程共享。

用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译后的代码等数据。

别名永久代(PermanentGeneration)

永久代也会垃圾回收,主要针对常量池回收,类型卸载(比如反射生成大量的临时使用的Class等信息)。

-XX:MaxPermSize设置上限

-XX:PermSize设置最小值

例:VM Args:-XX:PermSize=10M-XX:MaxPermSize=10M
运行时常量池(Runtime Constant Pool)是方法区的一部分。

Class文件中除了有类的版本、字段、方法、接口等信息外,还有一项是常量池(ConstantPool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

运行时常量池相对于Class文件常量池的一个重要特征是具备动态性:即除了Class文件中常量池的内容能被放到运行时常量池外,运行期间也可能将新的常量放入池中,比如String类的intern()方法。

当方法区满时,无法在分配空间,就会抛出内存溢出的异常(OutOfMemoneyError)。

Java8中已经没有方法区了,取而代之的是元空间(Metaspace)。

6.直接内存

直接内存并不是虚拟机运行时数据区的一部分。

在NIO中,引入了一种基于通道和缓冲区的I/O方式,它可以使用native函数直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

-XX:MaxDirectMemorySize设置最大值,默认与java堆最大值一样。

例:-XX:MaxDirectMemorySize=10M-Xmx20M

猜你喜欢

转载自blog.csdn.net/Code_shadow/article/details/81053023