【精通 JVM 原理】浅析 JavaAgent & Instru
浅析 JavaAgent & Instrumentation 机制
前言
本文主要内容
1、JVM的字节码指令,方法调用机制
2、Java类加载器
3、JavaAgent
4、Java Instrumentation
词汇说明
Java Virtual Machine (JVM)
什么是字节码?
机器码
机器码(machine code)是CPU可直接解读的指令。机器码与硬件等有关,不同的CPU架构支持的硬件码也不相同。
字节码
字节码(bytecode)是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。通常情况下它是已经经过编译,但与特定机器码无关。字节码主要为了实现特定软件运行和软件环境、与硬件环境无关。
字节码的实现方式是通过编译器和虚拟机器。编译器将源码编译成字节码,特定平台上的虚拟机器将字节码转译为可以直接执行的指令。
例如:C# IL,Java bytecode
JVM字节码执行模型及字节码指令集:
https://blog.csdn.net/lijingyao8206/article/details/46562933
JVM 虚拟机字节码指令表:https://segmentfault.com/a/1190000008722128
Java 源代码的编译和执行
Java 源代码的编译过程如下图:
JVM的运行时数据区的结构如下图:
字节码指令执行的数据结构是栈帧(Stack Frame),也就是在虚拟机栈中的栈元素。
JVM 虚拟机会为每个方法分配一个栈帧,因为虚拟机栈是LIFO(后进先出)的,所以当前线程正在活动的栈帧,也就是栈顶的栈帧,JVM规范中称之为“CurrentFrame”, 这个当前栈帧对应的方法就是“CurrentMethod”。
字节码的执行操作,指的就是对当前栈帧数据结构进行的操作。
桢栈的数据结构
一个JVM 进程在操作系统中的全局图如下:
讲到数据结构,就必须要看内存模型。
JVM 内存模型与运行时数据区
JVM运行时数据区包括:PC寄存器,JVM栈,本地方法栈,堆,方法区几个部分。
看图说话:
Java Class File 字节码文件,通过“Class Loader”加载到 “Runtime Data Area” 中,然后交给 “Execution Engine” 执行。
JVM 内存分配过程:
JVM运行时数据区图示: Memories of a Java Runtime :
JVM runtime memory
Class Method Area
Once a class bytecode is loaded by a JVM class loader, it’s passed to the JVM for further processing.
The JVM creates an internal representation of the class and stores it in the method area.
An example of a class method area is shown in above Figure. The following data areas are contained within the internal representation of a class:
-
Runtime Constant Pool contains constants used in a particular class. The constants can be of types int, float, double, and UTF-8. It also contains references to methods and fields.
-
Method Code is the implementation (opcodes) of all class methods.
-
Attribute and Field Values contain all named attributes and field values of a class. A field value points to a value stored in the runtime constant pool.
JVM Stack
每个栈帧对应着一个未运行完的函数,栈帧中保存了该函数的返回地址和局部变量。
栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。从逻辑上讲,栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等。
栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)。
Every thread has a private JVM stack. A stack is created during a thread startup time and its size can be static or dynamic. A JVM stack is used for storing stack frames as shown in Figure:
A new stack frame is created and pushed into a thread stack every time a method is invoked. A frame is popped when a method returns.
Though there may be multiple frames on a stack from nested method calls, only one frame is active at a given time for a thread.
A JVM throws a StackOverflowError when a thread needs a stack area larger than permitted or memory available. If a JVM stack is dynamically allocated, a JVM may throw an OutofMemoryError if insufficient memory is available to meet stack size increase request. It may also throw a OutofMemoryError if insufficient memory is available during initial stack allocation.
Java 方法调用执行机制
JavaAgent
Java Instrumentation
参考资料
https://indrabasak.github.io/java-runtime-memory/
https://blog.csdn.net/poiuyds/article/details/81196916