智能

一文解析总结Java虚拟机器器内存区域模型

一文解析总结Java虚拟机器器内存区域模型

最近抽空看了一点《深入理解Java虚拟机器》,本篇文章主要来总结一下Java虚拟机器内存的各个区域,以及这些区域的作用、服务物件以及其中可能产生的问题,作为大家的面试宝典。

首先我们来看一下Java执行时的资料区域,Java虚拟机器在执行Java程式的过程中会把它所管理的内存划分成若干个不同的资料区域,这些区域都有各自的用途,各自的建立和销毁的时间。有的区域随着虚拟机器程序的启动而存在,有些区域则依赖使用者执行绪的启动和结束而建立和销毁。

我们来看一下Java虚拟机器执行时的资料区

结合这张图,下面逐个来分析一下每个资料区域的特点。

1. 程式计数器

程式计数器是一块较小的内存空间,可以看作是当前执行绪所执行的字节码的行号指示器。什么意思呢?我们知道,CPU的计算时间是以分片的方式给到每个执行绪的(换句话说,所谓并行其实本质上还是序列),比如执行绪A执行到一个地方,CPU将控制权给了执行绪B,那么执行绪A重新获得CPU的资源时,如何恢复到刚才执行的地方呢?这就是程式计数器要干的事了!它能帮助执行绪A找到刚刚执行的地方,从而继续刚刚的执行。

为了执行绪切换后能恢复到正确的执行位置,就要求每个执行绪都需要有个独立的程式计数器,各条执行绪之间的计数器互不影响,独立储存。所以程式计数器是执行绪私有的。

另外,程式计数器是唯一一个在Java虚拟机器规范中没有规定任何OutOfMemoryError情况的区域。

2. Java虚拟机器栈

Java虚拟机器栈占有的内存空间也就是我们平常所说的“栈内存”,并且也是执行绪私有的,生命周期与执行绪相同。虚拟机器栈描述的是Java方法执行的内存模型:每个方法在执行的同时,都会建立一个栈帧,用于储存区域性变量表(基本资料型别,物件的引用和returnAddress型别)、算子栈、动态连结、方法出口等资讯。

区域性变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的区域性变数空间是完全确定的,在方法执行期间不会改变区域性变量表的大小。

每个方法被呼叫直至执行完成的过程,就对应着一个栈帧从虚拟机器栈中从入栈到出栈的过程。对于Java虚拟机器栈,有两种以尝情况:

如果执行绪请求的栈深度大于虚拟机器所允许的深度,将丢掷StackOverFlowError异常。

如果虚拟机器栈在动态扩充套件时,无法申请到足够的内存,就会丢掷OutOfMemoryError异常。

3. 本地方法栈

本地方法栈和虚拟机器栈所发挥的作用非常相似,它们之间的区别主要是:虚拟机器栈是为虚拟机器执行的Java方法(即字节码)服务的,而本地方法栈则为虚拟机器使用到的Native方法服务。

与虚拟机器栈类似,本地方法栈也会丢掷StackOverFlowError和OutOfMemoryError异常。

4. Java堆

Java堆是Java虚拟机器所管理的内存中最大的一块。Java堆在主内存中,是被所有执行绪共享的一块内存区域,其随着JVM的建立而建立,堆内存的唯一目的是存放物件例项和阵列。同时Java堆也是GC管理的主要区域。

Java堆在物理上不需要连续的内存,只要逻辑上连续即可。如果堆中没有内存完成例项分配,并且也无法再扩充套件时,将会丢掷OutOfMemoryError异常。

5. 方法区

方法区是所有执行绪共享的一块内存区域。用于储存已被虚拟机器载入的类资讯、常量、静态变数、即时编译器编译后的程式码等资料。方法区也有一个别名叫Non-heap(非堆),用来与Java堆区分。对于HotSpot虚拟机器来说,方法区又习惯成为“永久代(Permancent Generation)”,但这只是对于HotSpot虚拟机器来说的,其他虚拟机器的实现上并没有这个概念。相对而言,垃圾收集行为在这个区域比较少出现,但也并非不会来收集,这个区域的内存回收目标主要是针对常量池的回收和对型别的解除安装上。

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

6 执行时常量池

执行时常量池属于方法区。Class档案中除了有类的版本、字段、方法、界面等描述资讯外,还有一项资讯是常量表,用于存放编译期生成的各种字面常量和符号引用,这部分内容将在类载入后进入方法区的执行时常量池中存放(JDK1.7开始,常量池已经被移到了堆内存中了)。

也就是说,这部分内容,在编译时只是放入到了常量池资讯中,到了载入时,才会放到执行时常量池中去。执行时常量池县归于Class档案常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class档案中常量池的内容才能进入方法区的执行时常量池,执行期间也可能将新的常量放入池中,这种特性被开发人员利用的比较多的是String类的intern方法。

当方法区无法满足内存分配需求时,将丢掷OutOfMemoryError异常,常量池属于方法区,同样可能丢掷OutOfMemoryError异常。

下面针对Java内存区域模型做一下简单的总结。

最后

如果你现在在JAVA这条路上挣扎,也想在IT行业拿高薪,可以参加我们的训练营课程,选择最适合自己的课程学习,技术大牛亲授,7个月后,进入名企拿高薪。我们的课程内容有:Java工程化、高效能及分散式、高架构。效能调优、Spring,MyBatis,Netty源代码分析和大资料等多个知识点。如果你想拿高薪的,想学习的,想就业前景好的,想跟别人竞争能取得优势的,想进阿里面试但担心面试不过的,你都可以来,q群号为:956011797

注:加群要求

具有1-5工作经验的,面对目前流行的技术不知从何下手,需要瓶颈的可以加。

在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。

如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。

觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。

阿里Java高阶大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!