JAVA内存区域

一、图解

java方法区和永久区 java中的方法区_方法区

二、解释

1. 方法区

定义

方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据

补充
在JDK8之前的,大部分的Java程序员更愿意讲方法区称呼为“永久代”。这是因为当时的虚拟机的设计把垃圾回收的分代设计扩展至方法区,让永久代的方式实现方法区,试图可以让永久代的垃圾回收算法管理方法区。
但是随着时间发展至JDK8,永久代的概念被放弃。在实现层面上使用本地内存(Native Memory)来实现按方法区的设计。内容上有关静态变量等信息被移入方法区,另一部分移入本地内存中实现的元空间(Meta-space)。

个人解读

Java通用数据的静态变量与常量等数据的公共存储空间,也是线程公用的内存空间。

2.Java 堆(重点)

定义

Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java世界里“几乎”所有的对象实例都在这里分配内存。

个人解读

这里的Java堆就是广义上所分的堆内存。堆内存里面存储了java程序运行的几乎所有的java对象实例。鉴于对象实例的调用特点,固然是线程无关的区域。
但是大量的java对象的存储不会像是栈内存一般,生命周期是依赖线程的(其实应该特指栈帧)会及时消亡。因此也引出JAVA虚拟机的另一个重点垃圾回收

3. 虚拟机栈(重点)

定义

虚拟机栈描述的是一个java方法执行的线程私有的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。

补充

局部变量表存放了编译器克制的各种Java虚拟机基本数据类型(boolean、byte、short、char、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针, 也可能是指向一个代表对象的句柄或者其他于此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)

个人解读

在书中有一段话经常有人把Java内存区域笼统的分为堆内存(Heap)和栈内存(Stack),而“栈”通常就是指这里讲的虚拟机栈,或着更多情况下知识指虚拟机栈种局部变量表的部分

整个java虚拟机栈可能都是一个依赖线程存在的、对栈帧进行出入栈操作的、进而实现的java程序的执行的栈模型。

栈帧的出入栈操作就是学习期间的方法入栈出栈的实际解释

个人解读

4. 本地方法栈

定义

本地方法栈与虚拟机栈发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则是为虚拟机使用到的本地方法(Native)服务。

5. 程序计数器

定义

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在java虚拟机的概念模型里面,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等等的基础功能都需要依赖这个计数器完成

个人解读

个人理解:有点像是计算机组成原理里面的PC寄存器用来控制的程序流程的。
至于它的线程私有我是通过顺序执行的基础“线程”联想出来的,一旦一个线程的执行顺序可以被其他线程控制,就必会出现程序逻辑的执行错误。

6. 运行时常量池(补充)

定义

运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息之外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法去的运行时常量池中。

补充

这个其实就是对着书上做的摘抄。这部分的常量池的加载并不仅限于编译时期,在运行期间遭遇的量值也可已保存(String类)。

7. 直接内存(补充)

定义

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是《java虚拟机规范》中定义的内存区域。
它是在JDK1.4中加入的NIO类使用的一种全新I/O方式的依赖的内存区域,直接受到主机内存的管辖。间接收到Java堆里面的DirectByteBuffer对象的引用操作

个人理解

可以作为内存之外的一个拓展,不属于jvm的内存管理。如果想要了解可以看看NIO的IO操作模型。