JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

深入理解JVM运行原理:从内存布局到执行流程的全面解析

wys521 2024-11-01 15:16:20 精选教程 28 ℃ 0 评论

1、JVM内存模型

2、认识Java字节码,了解JVM如何运行的

Java AI.class字节码:

public AI();:这是AI类的构造方法。

Code::

0: aload_0:将当前对象引用(this)加载到操作数栈顶。

1: invokespecial #1:调用父类(假设是Object类)的构造方法

4: aload_0:再次将当前对象引用加载到操作数栈顶。

5: new #2:创建一个新的Person对象。

8: dup:复制新创建的Person对象的引用。

9: invokespecial #3:调用Person类的构造方法。

12: putfield #4:将新创建的Person对象赋值给当前对象的person字段。

15: return:返回,结束构造方法。

public static void methodA();:这是一个静态方法,没有参数,返回类型为void。

Code::

0: iconst_1:将整数常量1压入操作数栈。

1: istore_0:将这个整数存储到局部变量表的第0个位置

2: getstatic #5:获取静态字段System.out的引用。

5: ldc #6:将字符串常量"methodA"压入操作数栈。

7: invokevirtual #7:调用PrintStream.println(String)方法,输出字符串"methodA"。

10: return:返回,结束方法。

public void methodB();:这是一个实例方法,没有参数,返回类型为void。

Code::

0: iconst_2:将整数常量2压入操作数栈。

1: istore_1:将这个整数存储到局部变量表的第1个位置。

2: getstatic #5:获取静态字段System.out的引用。

5: ldc #8:将字符串常量"methodB"压入操作数栈。

7: invokevirtual #7:调用PrintStream.println(String)方法,输出字符串"methodB"。

10: aload_0:将当前对象引用加载到操作数栈顶。

11: invokevirtual #9:调用实例方法methodC()。

14: return:返回,结束方法。

public void methodC();:这是另一个实例方法,没有参数,返回类型为void。

Code::

方法与上面的methodB()相同,不解释了。

public static void main(java.lang.String[]);:主方法,程序的入口点。

Code::

0: new #10:创建一个新的AI对象。

3: dup:复制新创建的对象的引用。

4: invokespecial #11:调用AI类的构造方法。

7: astore_1:将新创建的对象的引用存储到局部变量表的第1个位置。

8: invokestatic #12:调用静态方法methodA()。

11: aload_1:将局部变量表第1个位置的引用(即新创建的AI对象)加载到操作数栈顶。

12: invokevirtual #13:调用实例方法methodB()。

15: return:返回,结束方法。

3、加载及代码执行流程

1、类加载和链接

  • 当Java程序启动时,JVM首先通过类加载器(ClassLoader)加载类文件,即.class文件。类加载器从文件系统、网络或其他来源读取类的字节码,并将其加载到JVM中。
  • 在加载之后,JVM会进行链接操作,包括验证(检查字节码的正确性)、准备(为静态字段分配内存并设置默认值)和解析(将符号引用转换为直接引用)。

2、创建对象和执行构造方法

  • 在main方法中,首先通过new指令创建了一个AI类的实例。这个指令会在Java堆上分配内存空间,并调用AI类的构造方法初始化对象。
  • 构造方法的字节码中,首先使用aload_0将当前对象引用(this)加载到操作数栈顶,然后调用父类(Object类)的构造方法进行初始化。
  • 接下来,使用new指令创建了一个Person类的实例,并调用其构造方法进行初始化。然后,使用putfield指令将新创建的Person对象赋值给当前对象的person字段。

3、方法调用和执行

  • 在main方法中,通过invokestatic指令调用了静态方法methodA。静态方法的调用不需要对象引用,直接通过类名和方法名进行调用。
  • methodA方法中,首先将整数常量1压入操作数栈,然后使用istore_0指令将其存储到局部变量表中索引为0的位置。接着,通过getstatic指令获取静态字段System.out的引用,并使用ldc指令将字符串常量"methodA"压入操作数栈。最后,通过invokevirtual指令调用PrintStream.println方法输出字符串"methodA"。
  • 在main方法中,通过invokevirtual指令调用了实例方法methodB。实例方法的调用需要使用对象引用。在该指令之前,使用aload_1指令将之前创建的AI对象引用加载到操作数栈顶。
  • methodB方法与methodA类似,只是输出的字符串不同。

4、返回和退出

  • 每个方法执行完毕后,都会使用return指令返回。对于返回类型为void的方法,直接使用return指令;对于返回类型为非void的方法,会将返回值压入操作数栈,然后使用相应的返回指令(如ireturn、areturn等)。
  • 当程序执行完毕或遇到异常情况时,JVM会退出并释放相关资源。

4、了解代码是如何被类加载器处理的?

类加载器的主要任务是将.class文件从文件系统或其他来源加载到内存中,并将其转换为Java Class对象。这个过程涉及到几个关键步骤,包括加载、链接和初始化。

类加载(Loading):
类加载器首先通过读取.class文件来加载类的字节码。这个.class文件包含了类的完整结构和元数据。当JVM启动时,它会使用系统类加载器(System ClassLoader)来加载AI类。系统类加载器会查找AI.class文件,并将其加载到内存中。

链接(Linking):
链接阶段包括验证、准备和解析三个步骤。

1、验证(Verification):验证阶段确保加载的类文件是正确和安全的。JVM会检查字节码是否符合Java虚拟机规范,并执行一些安全性检查,以防止恶意代码的执行。在代码中,AI类的字节码会经过验证,以确保其有效性和安全性。

2、准备(Preparation):准备阶段为类的静态变量分配内存,并将它们初始化为默认值。这意味着在这个阶段,JVM会为AI类的静态变量分配内存空间,并将其初始化为相应的默认值。例如,对于static int a,它会被初始化为0。

3、解析(Resolution):解析阶段将符号引用转换为直接引用。符号引用是代码中使用的类、方法或字段的名称,而直接引用是与目标相关的内存地址或其他直接引用信息。在代码中,解析过程会将AI类中引用的其他类或方法的符号引用转换为相应的直接引用,以便在运行时正确访问它们。

初始化(Initialization):
初始化阶段是执行类的<clinit>()方法的过程。<clinit>()方法是由编译器自动生成的,它包含了类中所有静态变量的赋值动作和静态代码块的内容。一旦<clinit>()方法执行完成,类就被认为已经初始化完成。

知识点:类加载器主要有三种:引导类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和系统类加载器(System ClassLoader)。引导类加载器负责加载核心类库,扩展类加载器负责加载Java扩展包,而系统类加载器则负责加载应用程序的类和资源。

类加载器使用双亲委派模型来处理类加载请求。当一个类加载器收到类加载请求时,它首先将请求委派给父类加载器去处理。只有当父类加载器无法处理请求时,才会由当前类加载器来处理。这种模型确保了Java核心类库的稳定性和安全性。


本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表