你还记得吗?你还记得吗?你还记得吗?从来没有记住过,又何来忘记呢!
内存结构可以说是面试100%会出现的!为了应付面试,赶紧百度、看书,结果面试官问的深一点就嗝屁了!还不如说不会呢,可是这么基础的知识点都不会,所谓的会也可能是理论层面的,我在网上看多了很多相关的文章,互相印证,大部分的文章都是理论,理论还是理论。没错理论是实践的基础,可是知行合一才是完整的。废话不多说了,下面进入正题。
内存区域的划分:
共享区域:堆、方法区
私有区域:程序计数器、栈、本地方法栈
注:1.8开始没有单独的方法区,而是在堆中分配一块区域作为方法区,通过命令查看内存情况可知,真的没有单独方法区
1:程序计数器
计数器到底记得是什么数呢?当前线程所执行的字节码的行号指示器。解释器就是通过计数器来控制分支、循环、跳转、异常处理、线程恢复等,为了保证每个线程正确执行,计数器是每个线程私有的。在形象一点就是查看class文件,code对应的每一行都是指令,计数器就是要记录当前栈正在执行的指令行,当线程切换后继续执行时,从上一次的指令行继续执行,
如果执行native方法,则计数器的值为空(undefined)
程序计数器特点:
线程私有、生命周期和线程相同、无OutOfMemoryError异常
2:虚拟机栈
线程私有的,和程序计数器的生命周期相同,虚拟机栈描述的是java方法执行的内存模型,每个方法执行时会创建一个栈帧。栈帧主要保存局部变量表、操作数栈、动态链接、方法出口,局部变量表存放了编译期可知的各种基本类型、对象引用(指针、句柄、对象的位置)、returnAddress类型(指向一条字节码指令)。线程请求的栈深度大于虚拟机允许的深度抛出StackOverFlowError(递归调用很容易抛出),如果虚拟机支持扩展空间,当无法申请到足够空间时抛出OutOfMemoryError(如果堆内存快用尽的时候,申请栈内存就会抛出)
虚拟机栈的特点:
线程私有、生命周期和线程相同、抛出StackOverFlowError和OutOfMemoryError、存放内容(局部变量表、操作数、动态链接、方法出口)
3:本地方法栈
和虚拟机栈的作用相同,只不过执行的是本地方法,而非java方法
4:堆
所有对象的实例和数据都要在堆上分配,堆还可以细分为新生代、老年代、Eden空间、From Survivor空间、To Survivor空间,从内存分配角度可以划出多个线程私有的分配缓冲区TLAB,无论怎么划分和存在内容无关,仍然是实例,划分的目的就是为了更好的回收内存,或者更快的分配内存。物理空间可以不连续,但是逻辑空间要连续,如果无法扩展抛出OutOfMemoryError,可通过-Xmx -Xms 控制,无法扩展抛出OutOfMemoryError
源码:
byte[] allocation1, allocation2, allocation3,allocation4;
allocation1 = new byte[1 * _1MB];
allocation2 = new byte[2 * _1MB];
allocation3 = new byte[3 * _1MB];
allocation4 = new byte[4 * _1MB];
打印内存情况
Heap Parameters:
Gen 0: eden [0x04800000,0x04c28068,0x05000000) space capacity = 8388608, 51.95436477661133 used
from [0x05100000,0x0517b108,0x05200000) space capacity = 1048576, 48.072052001953125 used
to [0x05000000,0x05000000,0x05100000) space capacity = 1048576, 0.0 usedInvocations: 1
Gen 1: old [0x05200000,0x05800030,0x05c00000) space capacity = 10485760, 60.000457763671875
可知内存的地址范围是0x04800000-0x05c00000
上图中的4个byte数组对应的内存地址为0x04800000、0x05500050、0x05300010、0x05200000,那么就足以说明这四个对象存储在堆里
堆的特点:共享内存、生命周期和虚拟机相同、抛出OutOfMemoryError,保存所有的new的实例
5:方法区
线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码数据,虚拟机规范描述方法区为的一个逻辑部分,别名非堆,主要是和堆区分开。无法扩展抛OutOfMemoryError,关于类的具体细节会有专门章节
方法区特点:
共享内存、生命周期和虚拟机相同、抛出OutOfMemoryError,保存类信息、常量、静态变量、即时编译器编译后的代码数据
6:常量池
运行时常量池是方法区的一部分,class文件中除了有版本、字段、方法、接口信息外还有一项信息是常量池,用于存放编译后生成的字面量和引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。运行过程中新的常量也可以放入常量池,允许扩展,无法扩展抛OutOfMemoryError
常量池特点:
共享内存、生命周期和虚拟机相同、抛出OutOfMemoryError,保存常量