【jvm】jvm的内存模型

前言: jvm的内存模型,应该是每个"高级java"程序猿必备的知识储备了,各大公司对高级的要求里几乎都有提到"深入理解Jvm的内存模型...",其实当你深入的理解了jvm的内存模型后,在以后代码的开发中,你会对变量,常量,类,方法的生命周期及作用域,异常等有更深入的理解,而不是像新手一样生搬硬套final static关键字的作用...如果没有这些知识储备,在你开发中碰到一些bug,看上去代码没啥问题,但却报错,然后你几乎无从下手,不知道问题出在了哪里...


计算机自诞生以来,发展极其迅速,以至于我们的电脑几乎熬不过5年就要换新的了...在频繁的更迭中,电脑的cpu变得越来越强大,运算速度几何倍的增长,于是磁盘的读写速度跟不上cpu的处理速度,内存开始登山舞台,再后来内存也吃不消cpu这膨胀的性能了,为了不被内存拖慢cpu性能,cpu产商开始为每个cpu提供一块高速缓冲内存,来缓解内存IO速度跟不上cpu处理速度的尴尬.所以我们曾用过的单核cpu电脑实际上是下图这样进行数据运算的:

再后来,cpu大哥觉得一个人单枪匹马太累了,需要有三头六臂才能满足人类对性能的要求,于是出现了多核CPU,多核CPU性能确实比原来提高太多,且基于高速缓存的存储交互很好的解决了处理器与内存之间的矛盾,但也引入了新的问题:缓存一致性问题.在多处理器系统中,每个处理器有自己的高速缓存,而他们又共享同一块内存当多个处理器运算都涉及到同一块内存区域的时候,就有可能发生缓存不一致的现象。为了解决这一问题,需要各个处理器运行时都遵循一些协议,在运行时需要将这些协议保证数据的一致性。这类协议包括MSI、MESI、MOSI、Synapse、Firely、DragonProtocol等。如下图所示:

之所以讲这么多硬件相关的东西,主要就是为了帮助大家理解jvm的虚拟机.

其实java虚拟机的内存模型是根据硬件设计的,基本上与计算机硬件保持一致,cpu处理线程,每个线程拥有自己的工作内存(类似于cpu的高速缓存),然后所有线程共享一块主内存.

当线程与内存区域进行交互时,数据从主存拷贝到工作内存,进而交由线程处理(操作码+操作数).

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

下面我们一起来看下jvm的"逻辑"内存模型图:

之所以称之为逻辑内存模型图,主要是因为是抽象出来的,并不是说Jvm的内存就跟上图一模一样实际存在的.

下面我们分别来看看这些组件分别是用来做什么的:

1.方法区:

用来存放一些已经被虚拟机加载的类信息,常量,静态变量,即时编译后的代码等数据,是各个线程共享的一块内存区域.

方法区的垃圾回收是极少的,这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。

根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常.

2.java堆

在java中,堆是占用内存最多的一块区域,对应内存上一块逻辑上连续空间,物理上不一定连续,由所有线程所共享,主要用来存放对象实例,几乎所有的对象实例化都在此块区域分配内存,这块区域也是垃圾回收的主要区域,这块区域由young区和Old区构成,如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常.

关于堆 更详细的可以参阅我另外一篇文章,专门介绍jvm垃圾回收的【jvm】jvm调优.

3.Java 虚拟机栈

java虚拟机栈是线程私有的,生命周期与线程相同,跟线程同生共死,虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执行时都会创建一个栈帧,用来存放局部变量表,操作栈,动态链接,方法出口等信息,每一个方法被调用直至完成对应着一个栈帧从虚拟机栈中从入栈到出栈的过程.

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress 类型.在Java 虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常;如果虚拟机栈可以动态扩展(当前大部分的Java 虚拟机都可动态扩展,只不过Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError 异常。

4.程序计数器

程序计数器是一块很小的内存空间,可以理解为它是当前线程所执行字节码的行号指示器.字节码解释器工作时就是靠这个程序计数器的值来决定下一步要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等都要依赖这个计数器来完成.为了保证互不影响,程序计数器被每个线程私有,如果正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java 虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。

5.本地方法栈

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务,语言不限...


关于Jvm的内存模型就简单介绍到这里,参考资料《深入理解java虚拟机》.

猜你喜欢

转载自blog.csdn.net/lovexiaotaozi/article/details/83579007