JVM内存划分

半世苍凉 提交于 2020-02-08 15:21:39

JVM中内存划分及其作用

运行时数据区:这部分由5部分组成,分别为程序计数器、虚拟机栈、本地方法栈、堆、方法区;其中程序计数器、虚拟机栈、本地方法栈是线程独有的(即每个线程都有如此一个区域),而堆与方法区是线程共享的。下面我们再分别从存储内容、是否会发生内存溢出来介绍各个区域。

一、            程序计数器:是当前线程所执行的字节码的行号指示器(记录当前线程执行到字节码文件的什么位置),没有规定任何内存溢出的情况;如果当前线程执行的是java方法,则计数器存储的是正在执行的字节码指令的地址,若当前线程执行的是本地方法(native修饰的方法),则计数器的值为空。

二、            虚拟机栈:描述的是java方法执行的内存模型,每个方法在执行的时候就会创建一个栈帧,栈帧就是在虚拟机栈中的,栈帧中存储得有局部变量表、操作数栈、动态链接、方法出入口等信息。在该内存区域可能会出现内存溢出的情况,当栈是不可扩展的,当栈满时再往栈中存元素就会发生StackOverflowError异常;当栈是可扩展的,栈一直扩展直至虚拟机内存不够时将会发生OutOfMemoryError异常。

三、            本地方法栈:与虚拟机栈是一样的,知识虚拟机栈针对的是java方法,而本地方法栈针对的是native方法。

四、            堆:我们创建的对象基本都是存储在堆上,也有例外,这里举几个列子后期的优化会使对象实例可能存储在其他的区域,还有Class对象是存储在方法区中的。JVM垃圾回收时主要是针对于堆内存的,因为对象存活的时间差异大,有的对象创建后就死亡,而有些对象却存活很久,如果这两类对象都一起回收时效率不高,也会较复杂;为了解决这个问题又将堆细分为新生代和老年代,并且又将新生代再细分为一个Eden区和两个survivor区,对新生代和老年代采用不同的垃圾回收算法。当然堆区也会发生内存溢出的情况,和虚拟机栈一样,堆区也是可扩展的,并且一般的虚拟机都是以可扩展的方式实现的,当堆中没有内存分配对象实例、并且无法扩展时就会发生OutOfMemoryError异常。可以通过Xms(最小值/初始值)和Xmx(最大值)来设置堆的最大值和最小值。

五、            方法区:用来存储已经虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等,通常这个区域也被称作永久代,以前在方法区中还存在一个重要的区域字符串常量池,JDK1.7的HotSpot后将字符串常量池移出方法区。除此以外方法区中还有一个非常重要的区域:

运行时常量池:常量池用于存放在编译期生成的字面量和符号引用,在类加载后常量池中的内容将会进入运行时常量池。运行时常量池具有动态性,即除了Class文件中常量池的内容外,运行期间也可以将新的常量放入运行时常量池中。

方法区同样会出现内存溢出的情况,当方法区无法满足内存分配的需求时将会抛出OutOfMemoryError异常。

在介绍完运行时数据区后再介绍一种内存区域:直接内存,它不属于运行时数据区也不属于JVM规范中的内存,在java中NIO可以直接操作这块区域。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!