一, JVM 运行起来, 就会给内存划分空间, 这块空间成为运行时数据区. 运行时数据区主要划分为以下几部分内容:
1. 栈
每一个线程运行起来的都会对应一个栈(线程栈), 栈中的数据是该线程独有的, 不会产生资源共享的情况, 因此栈是线程安全的.
栈当中存放的是栈帧, 当线程调用方法时, 就形成一个栈帧, 并将这个栈帧进行压栈操作, 方法执行完之后进行出栈操作.
这个栈帧中包括: 局部变量, 操作数栈, 指向当前方法对应类的常量池引用, 方法返回地址等信息
2. 本地方法栈
本地方法栈的机制和栈相似, 区别在于: 栈运行的是 java 方法, 而本地方法栈中运行的是本地方法.
本地方法是指 JVM 需要调用非 Java 语言所实现的方法,
例如 C 语言. 在 JVM 规范中, 没有强化性要求实现方一定要划分出本地方法栈 (例如: HotSpot 虚拟机将本地方法栈和栈合二为一) 和具体实现(不同的操作系统, 对 JVM
规范的具体实现都不一样).
3. 程序计数器
程序计数器也可以成为 PC 寄存器, 通俗的讲就是指令缓存, 它主要用来缓存当前程序执行的下一条指令的地址, CPU 根据这个地址找到将要执行的指令. 这个寄存器是 JVM
内部实现的, 不是物理概念上的计数器, 不过和 JVM 的实现逻辑一样.
4. 堆
堆内存主要存放创建的对象和数组, 堆内存在 JVM 中是唯一的, 被所有的线程说共享. 堆里面每一个对象都存放实例的实例变量, 堆内存中的对象没有被引用, 会自动被 java 的垃圾回收机制回收.
当在方法中定义了局部变量, 如果变量是基本数据类型, 直接存放在栈内存中, 如果这个变量是引用数据类型, 会将变量值存放在堆内存中, 栈内存中只存放引用地址.
5. 方法区
方法区在 JVM 中也是非常重要的一块内存区域, 和堆一样, 方法区可以被多个线程共享. 主要存放每一个被加载的 class 的信息
扩展: 每一个被加载的 class 信息有哪些东西呢?
class 信息主要包含魔数 (确定是否是一个 class 文件), 常量池, 访问标志(当前的类是普通类还是接口, 是否是抽象类, 是否被 public 修饰, 是否使用了 final 修饰等描述信息......), 字段表集合信息(使用什么访问修饰符, 是实例变量还是静态变量, 是否使用了 final 修饰等描述信息.....), 方法表集合信息(使用什么访问修饰符, 是否静态方法, 是否使用了 final 修饰, 是否使用了 synchronized 修饰, 是否是 native 方法......) 等内容.
当一个类加载器加载了一个类的时候, 会根据这个 class 文件创建一个 class 对象, class 对象就包含了上述的信息. 后续要创建这个类的实例, 都根据这个 class 对象创建出来的.
6. 常量池
常量池是方法区的一部分. 存放 class 中最重要的资源, JVM 为每一个 class 对象都维护者一个常量池
来源: http://www.bubuko.com/infodetail-3301398.html