JVM面试(二)内存区域划分

内存区划分

Java虚拟机在执行Java程序的过程中会把它锁管理的内存划分为若干个不同的数据区域。 这些区域有各自不同的用途,以及创建和销毁的时间。 有的区域随着虚拟机的进程一直存在,有的区域依赖用户线程的启动和结束而建立和销毁。

根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存,包含一下几个运行时的数据区域。如图:

一般我们面试的时候,都是笼统的说:堆、栈、以及方法区,JDK 8之后方法区变为"元空间"。

这个说法不错,下面我们详解一下。

程序计数器

程序计数器区域⼀块内存较小的区域,它⽤于存储线程的每个执行指令,每个线程都有自己的程序计数器,此区域不会有内存溢出的情况。

由于Java虚拟机的多线程是通过线程的轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器都只执行一个线程。

那么为了每次切换线程后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器, 所以这个程序计数器区域,是一个线程私有的内存。

虚拟机栈与本地线程栈

在很多情况下,我们都是把这两个合在一起说的。

两方面的原因,一个是《Java虚拟机规范》对本地方法栈使用的语言、使用方式等没有任何规定。 二是有些虚拟机确实把这两个合二为一,比如Hot-Spot虚拟机。

如果按照我这里的浅显理解的话,他们之间的区别可以这么说。

虚拟机栈的生命周期与线程相同,主要就是存储线程执行相关的局部变量信息。

本地方法栈也是如此,但是所执行的内容可能是虚拟机本地方法Native。

所以我们在面试的时候,可以只说虚拟机栈,甚至直说本地方法栈都可以。(在我面试数十次的经历中,确实没有遇到,挑这两个问区别的)

回到虚拟机栈,在每个方法被执行的时候,Java虚拟机都会在这个线程栈中创建一个"栈帧",用于存储局部变量表,操作数栈,方法出口等等信息。每一个方法被调用,直到执行完毕,就对应着一个栈帧从入栈到出栈的过程。

因为我们线程调用方法是一层层递进的,所以这个栈帧也是一层层叠加。当调用深度超过虚拟机所允许的深度时,就会抛出StackOverflowError异常。

还有一个情况是,栈帧层层递进的时候,虚拟机栈也是在不断增大。

如果栈的内存不足,并且提前分配好不能扩展;或者是扩展的时候无法申请到足够的内存,就会发生OutOfMemoryError异常。

堆区

堆区是各个线程共享的区域。

这也是老生常谈的问题,主要存放JVM启动时创建的数组和对象实例,还有垃圾回收也主要在堆区发生,还有分代模型等等巴拉巴拉。

具体内容我们可以到分析垃圾回收的时候详细说下。

需要注意的是,堆区也是可以被固定大小的,当内存不足无法扩展时,也会抛出OutOfMemoryError异常。

方法区

与堆区一样,也是各个线程共享的区域。

主要存储那些常亮,静态变量,代码缓存等数据。虽然《Java虚拟机规范》中把方法区描述为一个堆区的逻辑部分,但是名字却为"Non-Heap" 非堆,这就是要与堆区做区分。

这里不得不提一下"永久代" 这个概念,以前很多时候都是把永久代与方法区混为一谈。

这是因为HotSpot虚拟机的设计团队把垃圾收集器的分代设计扩展到了方法区,把方法区称为永久代来管理垃圾回收机制。

但是后来又把永久代的概念放到了本地内存中,一直到JDK8 之后,完全放弃了永久代的概念,改为在本地内存新实现的"元空间"来代替

粗略来说,就是最早时候方法区=永久代,后来统一并入本地内存的"元空间"中。

运行时常量池

也是方法区的一部分,主要 存储Class文件中编译期生成的各种字面量与符号引用

字面量是源代码中的固定值的表示法,即通过字面我们就能知道其值的含义。字面量包括整数、浮点数和字符串字面量;

符号引用包括类符号引用、字段符号引用、方法符号引用和接口方法符号引用。符号引用就是⼀个字符串,只要我们在代码中引用了⼀个非字面量的东西,不管它是变量还是常量,它都只是由⼀个字符串定义的符号,这个字符串存在常量池里,类加载的时候第一次加载到这个符号时,就会将这个符号引用(字符串)解析成直接引用(指针)。

相关推荐
❀͜͡傀儡师11 小时前
10个高并发场景的技术面试问题
面试·职场和发展
青莲84311 小时前
Java并发编程基础与进阶(线程·锁·原子类·通信)
android·前端·面试
月明长歌11 小时前
JavaThread类详解核心属性、常用方法与实践
java·开发语言·jvm
kaico201811 小时前
JVM的垃圾回收
开发语言·jvm
YuTaoShao11 小时前
【LeetCode 每日一题】1339. 分裂二叉树的最大乘积
算法·leetcode·职场和发展
zfj32111 小时前
java垃圾收集 minorgc majargc fullgc
java·开发语言·jvm·gc·垃圾收集器
leoufung11 小时前
LeetCode 172. Factorial Trailing Zeroes 题解
算法·leetcode·职场和发展
天才测试猿11 小时前
软件测试之bug分析定位技巧
软件测试·python·selenium·测试工具·职场和发展·测试用例·bug
烟沙九洲11 小时前
JVM 堆内存分代
java·jvm
进击的小头11 小时前
18_C语言算法面试与进阶:高频算法题实战与学习路线规划
c语言·算法·面试