一、Java内存区域
![](https://img-blog.csdnimg.cn/20200702224509392.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTIzMTkyOA==,size_16,color_FFFFFF,t_70)
再来个总结的表,然后一一再细说:
内存区域 | 线程隔离 | 作用 | 配置参数 | 异常 | 其他说明 |
---|---|---|---|---|---|
程序计数器 | 隔离 | 字节码行号指示器 | —— | —— | |
虚拟机栈 | 隔离 | 栈帧形式存储局部变量表、操作栈、动态链接、方法出口等信息,执行java方法 | -Xss | StackOverflowError OutOfMemoryError |
|
本地方法栈 | 隔离 | 执行本地方法 | -Xoss | StackOverflowError OutOfMemoryError |
连续内存 |
堆 | 共享 | 保存对象实例 | -Xms -Xmx |
OutOfMemoryError |
允许不连续 |
方法区 | 共享 | 存储类型信息、常量、静态变量、即时编译器编译后的代码缓存等数 | -XX:PermSize:16M -XX:MaxPermSize:64M |
OutOfMemoryError | 允许不连续 |
运行时常量池 | 共享 | 存储各种字面量与符号引用 | 允许不连续 方法区一部分 |
1.1 程序计数器
程序计数器是一块较小的内存,属于线程隔离区域,是当前线程所执行的字节码的行号指示器。
字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
1.2 虚拟机栈
这块内存区域就是我们常说的“栈”,也是线程私有或线程隔离的。生命周期与线程相同。
虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
经常有人把Java内存区域笼统地划分为堆内存(Heap)和栈内存(Stack),这种划分方式直接继承自传统的C、C++程序的内存布局结构,在Java语言里就显得有些粗糙了,实际的内存区域划分要比这更复杂。不过这种划分方式的流行也间接说明了程序员最关注的、与对象内存分配关系最密切的区域是“堆”和“栈”两块。其中,“堆”在稍后笔者会专门讲述,而“栈”通常就是指这里讲的虚拟机栈,或者更多的情况下只是指虚拟机栈中局部变量表部分。
1.3 本地方法栈
Native Method Stacks
这块区域和上面的虚拟机栈类似,只是虚拟机栈执行的是Java方法(也就是字节码),而本地方法栈执行的虚拟机本地的方法。
HotSpot是将虚拟机栈和本地方法栈合并在一起。
1.4 堆
1.5 方法区
方法区和堆一样是线程共享的。
1.6 运行时常量池
这个常量池不是一个新的区域,它只是方法区的一个部分。