3.认识JVM-运行时数据区
目录
1.认识JVM之Classfile:https://www.cnblogs.com/nuti/p/16270652.html
2.认识JVM之类加载机制:https://www.cnblogs.com/nuti/p/16270672.html
3.认识JVM之运行时数据区: https://www.cnblogs.com/nuti/p/16270703.html
4.认识JVM之编译器: https://www.cnblogs.com/nuti/p/16270741.html
5.认识JVM之垃圾收集器: https://www.cnblogs.com/nuti/p/16270755.html
6.认识JVM之JVM内存模型: https://www.cnblogs.com/nuti/p/16270816.html
书接上文,https://www.cnblogs.com/nuti/p/16270672.html 这次轮到了运行时数据区
RuntimeDataAreas
0.引入介绍
RuntimeDataAreas 也叫做JVM运行时数据区
The Java Virtual Machine defines various run-time data areas that are used during execution of a program. Some of these data areas are created on Java Virtual Machine start-up and are destroyed only when the Java Virtual Machine exits. Other data areas are per thread. Per-thread data areas are created when a thread is created and destroyed when the thread exits.Java虚拟机定义了在程序执行期间使用的各种运行时数据区域。其中一些数据区域是在Java Virtual Machine启动时创建的,只有在Java Virtual Machine退出时才会销毁。其他数据区域是每个线程的。每个线程的数据区域在线程创建时创建,在线程退出时销毁。
看一下官方的文档 可以看出 一部分是进程相关 一部分是线程相关
照着这个图 我们就可以看到
时数据区分为 方法区、堆、java虚拟机栈、pc寄存器、本地方法栈
这样的话 就可以分为2大范围 5个内容
1.进程生命周期
进程说明当前里面的数据会被所有线程共享,会有线程安全的问题
1.1.方法区 Method Area
It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.它存储每个类的结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括在类、实例初始化和接口初始化中使用的特殊方法说人话就是方法区中储存的是类的元数据信息,模板信息(这些模板信息可以让你接下来在堆中创造所谓的对象实例,你比如在堆中new一个数据 那这个类所谓的那些数据字段从何而来就是在这里)If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.如果方法区域中的内存不能满足分配请求,Java虚拟机就会抛出OutOfMemoryError
1.2.堆 Heap
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.Java虚拟机有一个在所有Java虚拟机线程之间共享的堆。堆是运行时数据区域,所有类实例和数组的内存都是从这里分配的。If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError如果计算需要比自动存储管理系统所能提供的更多的堆,Java Virtual Machine就会抛出OutOfMemoryError。
说人话就是 储存的是类的实例和对象 如果超了就会发生OOM
1.2.1.Java对象内部布局
一个对象在内存中包括3个部分:对象头 实例数据 对其填充
比如说 new User();
实例数据:里面有boolean/int/long/refernece那么大小就是 1+4+8+8=21字节(byte)
对象头:没有数组的话 markword(8)+classPointer(8) = 16字节
MarkWord:储存了分带年龄锁等标记ClassPointer:代表了我在堆内存中创建对象那么这个对象在方法区是在哪呢?
我属于谁 我的模板信息在哪里多大?
对其填充:21+16 = 37 那么对其填空就填3 因为是8的倍数
8的倍数只是方便计算机去快速的访问
这样下来一个对象大概就是几十个字节 当然这个只是粗略印象 一个对象多少个字节其实可以这样算出来
1.2.2.堆执行方法区
这样在堆中创建一个对象 对象里面会指向了方法区的具体元信息
那么什么情况 会方法区指向栈呢?往下看
1.2.3.方法区指向堆
例子:
private static Object obj = new Object();
- 左边private static Object obj 会放在方法区
- 右边 new Object()会放在堆里面
想这种静态成员变量就会由方法区指向堆
2.线程生命周期
每个线程都会有各自的一分数据 不会存在线程安全的问题
2.1.Java虚拟机栈 Java Threads
一路走到这里类已经丢到内存中了,那么如何去执行呢?
Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread. A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.每个Java虚拟机线程都有一个私有的Java虚拟机堆栈,与线程同时创建。一个Java虚拟机栈存储帧(§2.6)。Java虚拟机堆栈类似于传统语言(如C)的堆栈:它保存局部变量和部分结果,并在方法调用和返回中发挥作用。因为除了push和pop帧外,Java Virtual Machine堆栈永远不会被直接操作,所以帧可以被堆分配。Java虚拟机堆栈的内存不需要连续。
说人话就是:
- 虚拟机栈是一个线程运行的区域,保留着一个线程中方法的调用状态,也就是一个java线程的运行状态,所以是私有的,随着线程的创建而创建。
- 每一个被执行的方法 为改栈中的栈帧,为一个方法对应一个栈帧,每次调用一个方法就会让栈中压入一个栈帧 一个方法调用完成 就会把该栈帧从栈弹出。
方法要去被执行 那么就一定需要交给某个线程,下面先看一段代码理解一下
比如说现在有一串代码
void a(){ b(); } void b(){ c(); } void c(){ }
过程:【先进后出】
- 最先调用A,A作为栈帧压入栈底
- A调用B,B作为栈帧压在A上面
- 同理 C作为栈帧压在B上面
- 这个时候C完成操作进行返回,C就会弹出栈
假设:C方法中 引入C方法,这个时候栈中会继续往下压入栈帧C,C无限叠加最后会报错异常If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError栈帧溢出异常If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.也有可能会OOM异常
- C弹出后将值返回到B栈帧,B操作完成后继续弹出栈
- 最后到A。这个时候都处理完成则A也弹出栈
2.1.1.栈帧
看一下栈帧的结构
- 局部变量表local Variables
存储局部变量
类似下面标记到的都是局部变量
- 操作数栈Operand Stacks
iconst_3:把3压入操作数栈的栈底
astore_0:将操作数栈中的3拿出来复制给局部变量0
所以:op1 = 3 也就是iconst_3 和astore_0 的结合。这样也能发现op1=3这个操作其实不是原子性的
那么问题来了?他是怎么知道具体的下标的呢?为什么op1就代表了是局部变量表的中的0?
先来看一下官网原文:
On class method invocation, any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language). Any parameters are subsequently passed in consecutive local variables starting from local variable 1.
说人话就是如果是static修饰的下标从0开始 否则就从1开始
- 动态链接Dynamic Linking
将符号引用转换为直接引用
- 方法的返回:Normal Method Invocation Completion正常返回/Abrupt Method Invocation Completion异常返回
为了让后续的方法能够顺利的执行
2.1.1.1.栈引用堆
2.2.程序计数器 Pc Register
The Java Virtual Machine can support many threads of execution at once (JLS §17). Each Java Virtual Machine thread has its own pc (program counter) register. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method (§2.6) for that thread. If that method is not native
因为Java虚拟机可以支持多个线程同时执行。每个Java虚拟机线程都有自己的pc(程序计数器)寄存器。在任何时候,每个Java虚拟机线程都在执行单个方法的代码,即该线程的当前方法(§2.6)。如果那个方法不是本地的
因为java支持多线程,cpu进行时间片切换的时候,他得记录之前运行的方法是哪个。则计数器记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的是Native方法,则这个计数器为空,因为那是c++写的他就没法在java层面进行维护
2.3.本地方法栈 Native Method Stacks
An implementation of the Java Virtual Machine may use conventional stacks, colloquially called "C stacks
Java虚拟机的实现可以使用传统堆栈,通俗地称为“C堆栈”
类比java虚拟机栈
比如:Object的hashCode java语言没有去实现
比如上面c方法中使用了hashcode这个hashcode就肯定不能放在java虚拟机栈内 那么就放在本地方法栈中,通过动态链接进行链接