您的位置:首页 > 编程语言 > Java开发

《深入理解JAVA虚拟机》笔记3——java内存区域

2016-10-09 23:05 218 查看
一、java的运行时数据区域

java的运行时数据区域共分为以下两部份:

第一部份:

1)方法区

2)虚拟机栈

3)本地方法栈

4)堆

5)程序计数器

第二部份:

1)执行引擎(执行"本地库接口")

2)本地库接口(调用本地方法库)

1、程序计数器

在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的招待位置,每条线程都需要有一个独立的程序计数器,各条线程这间的计数器互不影响,独立存储,我们称这类存储区域为“线程私有”的内存。

如果线程正在执行一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是native方法,这个计数器值则为空。此内存区域是唯一一个在java虚拟机规范中没有任何OutOfMemoryError情况的区域。

2、Java虚拟机栈

Java虚拟机栈也是线程私有的,它的生命周期和线程相同。虚拟机栈描述的是Java方法执行的存内模型:每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息。

经常有人把java存存区域分为堆内存和栈内存,其中的栈就是指虚拟机栈,或者说虚拟机栈中的局部变量表部份。

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress类型(指向了一条字节码指令的地址)。

64位长度的long和double类型的数据会占用2个局部变量空间(slot),其余的数据类型只占1个。

如果线程请求的深度大于虚拟机允许的深度,将抛出StackOverFlowError异常。

3、本地方法栈

本地方法栈是为虚拟机使用到的native方法服务,本地方法栈也会抛出StackOverFlowError和OutOfMemoryError异常。

4、Java堆

随着JIT编译器的发展和逃逸分析技术的成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也渐渐变得不是那么绝对了。

5、方法区

方法区和Java堆一样,是各线程共享的内存区域,用于存放已被虚以后就机加载 的类信息、常量、静态变量、即量编译后的代码等数据

很多人愿意把方法区称为“永久代”,本质上两者并不等价,仅仅是因HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已。

这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载。

6、运行时常量池

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

java语言并不要求常量一定只能在编译期产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入常量池。

7、直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域,但是这部分内存也被频繁的使用,而且也可能导致OutOfMemeryError异常出现。

9、对象访问

一个指向对象的引用应该通过哪种方式去定位,主流的方式有两种:使用句柄和直接指针。

10、java堆溢出

通过参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机中出现内存溢出异常时Dump出当前的存存堆转储快照以便事后进行分析。

11、虚拟机栈和本地方法栈溢出

在HotSpot虚以后就机中,栈容量只由-Xss参数设定。

》如果线程请求的深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常

》如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

实验表明:在单个线程下,无论是由于栈帧太大,还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常。

每个线程分配到的栈容量越到,可以建立的线程数量就越少,建立线程的时候就越容易到剩下的内存耗尽。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: