第一章 深入理解jvm内存模型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/han1196639488/article/details/79855753

java的内存模型

一.运行时数据区域
这里写图片描述


java虚拟机在程序执行时会创建不同的运行时数据区,有的区域会随着虚拟机启动而存在,有的会随着用户线程存在而创建,jvm内存模型分为下面具体五部分:
这里写图片描述

1.程序计数器

程序技术器是较小的一块内存区域,可以看做是程序执行的字节码的行号指示器,字节码解释器工作就是通过改变这个计数器来改变下一条执行的字节码指令,循环,异常处理,跳转,线程回复等功能。
由于jvm的多线程执行时由cpu控制循环切换线程并分配处理器执行时间进行执行,所以就需要这个程序计数器来操作,每个线程拥有自己私有的程序计数器用来记录程序执行位置。
如果程序执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码的指令的地址,如果是native方法,则这个计数器的值为空。此区域是唯一一个基本不会出现oom的区域。

2.java虚拟机栈
与程序计数器一样,java栈也是线程私有,他描述的是java方法执行的内存模型,每个方法在执行的时候会创建栈帧。这个栈帧会包含局部变量表,操作数栈,动态链接,方法出口。方法的调用与结束,对应的是java栈帧的入栈和出栈。大多数人把java内存区域划分为java栈和java堆内存区域,这个划分比较粗糙,说明大多数只关注这个两个区域的问题,这个所指的栈就是java虚拟机栈,进一步其实关注的是局部变量表的内容。

局部变量表存放了编译期间可知的基本数据类型(boolean,byte,int,long…….),对象引用(可能是对象的起始的引用指针,也可能是对象的句柄)和returnAdress类型。
如果线程请求java栈的深度大于虚拟机所允许的深度,则会抛出stackoverflow异常,如果在申请内存区域时,无法获得足够内存,则会抛出oom。

3.本地方法栈
本地方法栈与java虚拟机栈非常相似,他们的区别只是,java虚拟机栈是为虚拟机执行java方法服务,而本地方法栈是为java的native方法服务,如:hashcode()等方法。与java虚拟机栈一样,本地方法栈也会抛出oom异常和Stack Overflow

4堆内存
Java Heap为Java堆内存,是java虚拟机管理内存中最大的一块,它是被所有线程共享的一块内存区域,在虚拟机启动时创建。java堆内存存放对象实例,几乎所有的对象实例都在这里分配空间,也是垃圾回收的主要区域。
垃圾回收采用分代回收的方法,因此堆内存被分为 新生代,老年代:再细分一点就是:Eden空间,from Survivor空间, To Survivor空间等。从内存分配的角度看,线程共享的java堆中可能划分出多个线程私有的分配缓冲区。

5.方法区

方法区和堆内存一样,是线程共享的内存区域,用于存放已加载的类信息,常量,静态变量,以及即时编译器编译后的代码等数据。

6.运行时常量池

扫描二维码关注公众号,回复: 4704120 查看本文章

运行时常量池是方法区的一部分,class信息除了版本,字段,方法,接口等信息外,还有常量池,用于存放编译期间生成的各种字面量和符号引用。运行时常量池也会受到方法区的限制,当不能分配内存时会抛出oom

7.直接内存

直接内存并不是java虚拟机运行时数据区的一部分,也不是java虚拟机规范中的内存区域,但是这个区域也被频繁使用,也会造成oom。
在jdk引入了nio的概念,引入了一种基于通道和缓冲区的io方式,他可是直接使用native库中的方法直接分配堆外内存,然后通过存储在java堆中的DirecteByteBuffer对象进行对这块内存进行操作。这样能在一些场景中显著提高性能。因为避免了在java堆中和native堆中来回复制数据。这个地方受到本机内存的大小的限制,当使用nio时,并且本机内存不足时会造成oom。

猜你喜欢

转载自blog.csdn.net/han1196639488/article/details/79855753