- Java的内存结构布局
JVM的内存结构主要由三大块:堆内存、方法区、栈。堆内存时JVM中最大的一块,由年轻代和老年代组成。年轻代又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,三部分默认情况下为8:1:1的比例分配空间。
下图更详细的描述了Java内存各部分的分配情况,以及通过哪些参数来控制各个区域的大小。
控制参数
-Xms设置堆的最小空间大小。
-Xmx设置堆的最大空间大小。
-XX:NewSize设置新生代最小空间大小。
-XX:MaxNewSize设置新生代最大空间大小。
-XX:PermSize设置永久代最小空间大小。
-XX:MaxPermSize设置永久代最大空间大小。
-Xss设置每个线程的堆栈大小
通过上图可以看出,栈中又包含程序计数器(Program Counter Register)、JVM栈(JVM Stacks)和本地方法栈(Native Method Stacks)。
下面是对JAVA内存各个区域的详细介绍:
Java堆:
Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。Java堆的目的主要是存放对象实例,几乎所有的对象实例都在这里分配内存(TLAB(Thread Local Allocation Buffer)并不是分配在堆上,参见http://blog.csdn.net/rickiyeat/article/details/76802085?locationnum=4&fps=1),所以Java堆是Java虚拟机管理的内存中最大的一块。
Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。Java堆是垃圾收集器管理的主要区域。
如果在堆中没有内存来完成实例分配,并且堆也无法扩展时,将会抛出OutofMemoryError异常。
方法区(Method Area):
方法区与Java堆一样,也是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。(所谓即时编译器的定义:即时编译器(Just In Time Compiler) 简称JIT,JAVA程序最初是通过解释器(Interpreter)进行解释执行的,当JVM发现某个方法或代码块运行特别频繁的时候,就会认为这是“热点代码”(Hot Spot Code)。为了提高热点代码的执行效率,就会将这些“热点代码”编译成与本地机器相关的机器码,进行各个层次的优化。 完成这个任务的编译器就是即时编译器(JIT))
根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
程序计数器(Program Counter Register):
程序计数器的作用可以看做是当前线程所执行的字节码的行号指示器,是线程私有的。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器的值则为空。
此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
JVM栈:
Java虚拟机栈是线程私有的,它描述的是Java方法执行的内存模型:每个方法被执行的时候都会创建一个栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。局部变量表存放了编译器可知的各种基本数据类型、对象引用和returnAddress类型。
在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。
本地方法栈(Native Method Stacks):
本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。
转载自:https://www.cnblogs.com/ityouknow/p/5610232.html