JVM的类加载通过ClassLoader及其子类来完成,分为Bootstrap ClassLoader、Extensin ClassLoader、System ClassLoader(在Sun JDK中对应的类名为AppClassLoader)及 User-Defined ClassLoader,其关系如下图:
1.Bootstrap ClassLoader Sun JDK 采用C++实现了此类,此类并非ClassLoader的子类,在代码中没有办法拿到这个对象,Sun JDK 启动时会初始化此ClassLoader,并由ClassLoader完成$JAVA_HOME 中jre/lib/rt.jar里所有class文件的加载;
2.Extension ClassLoader JVM用此ClassLoader来加载扩展功能的一些jar包,例如JDK中dns工具jar包等,对应的类名为ExtClassLoader;
3.System ClassLoader JVM 用此ClassLoader来加载启动参数中指定的Classpath中的jar包及目录,在Sun JDK中ClassLoader对应的类名为AppClassLoader;
4.User-Defined ClassLoader 这是开发人员继承ClassLoader抽象类自行实现的ClassLoader,可以用加载非Classpath中的jar及目录、还可以在加载之前对class文件做一些动作,例如解密等;
JVM会保证同一个ClassLoader实例对象中只能加载一次同样名称的Class
Cloader抽象类提供了几个关键的方法
-
loadClass 此方法负责加载指定名字的类,ClassLoader的实现方法为先从已经加载的类中寻找,如没有,则继续从 parent ClassLoader中寻找;如果仍然没有找到,则从System ClassLoader中寻找,最后再调用findClass方法来寻找;如果最终没有找到就抛出ClassNotFoundException;
-
findLoaderClass 方法负责从当前ClassLoader实例对象的缓存中寻找已加载的类,调用的为native的方法;
-
findClass 此方法直接抛出ClassNotFoundException,因此要通过覆盖loadClass或此方法来以自定义的方式加载相应的类;
-
findSystemClass 此负责从System ClassLoader 中寻找,如未找到,则继续从Bootstrap ClassLoader 中寻找,如果仍然未找到,则返回null;
-
defineClass 此方法负责将二进制的字节码转换成Class对象,如果二进制的字节码的格式不符合JVM Class文件的格式,则抛出ClassFormatError;如果生成的类名和二进制字节码中的不同,则抛出NoClassDefFoundError;如果加载的class是受保护的、采用不同签名的或者类名是以java.开头的,则抛出SecurityException;如果加载的class在此ClassLoader中已加载,则抛出LinkageError;
-
resolveClass 此方法负责完成Class对象的链接,如果链接过,则会直接返回;
3.类的执行机制
在源码编译阶段源码编译为JVM字节码,JVM字节码是一种中间代码的方式,要由JVM在运行期对其进行解释并执行,这种方式称为字节码解释执行方式;
1.字节码解释执行
JVM采用了invokestatic,invokevirtual,invokeinterface和invokespecial四个指令来执行不同的方法调用。
invokestatic对应的是调用static方法,invokevirtual对应的是调用对象实例的方法,invokeinterface对应的是调用接口的方法,invokespecial对应的是调用private方法和编译源码后生成的<init>方法;
Sun JDK基于栈的体系结构来执行字节码,基于栈方式的好处为代码紧凑,体积小,线程在创建后,都会产生程序计数器(pc)(或称为PC registers)和栈(Stack);PC存放了下一条要执行的指令在方法内的偏移量;栈中存放了栈帧(StackFrame),每个方法每次调用都会产生栈帧。栈帧主要分为局部变量区和操作数栈两部分,局部变量区用于存放方法中的局部变量和参数,操作数栈中用于存放方法执行过程中产生的中间结果,栈帧中还会有一些杂用空间,例如指向方法已解析的常量池的引用、其他一些JVM内部实现需要的数据等;
2.编译执行
解释执行的效率较低,Sun JDK在执行过程中对执行频率高的代码进行编译,对执行不频繁的代码则继续采用解释的方式;在编译上Sun JDK提供了两种模式:client compiler(-client)和server compiler(-server)。
client compiler又称为C1,较为轻量级,只做少量性能开销比高的优化,它占用内存较少,适合于桌面交互式应用,其他方面的优化主要有:
- 方法内联 这种方法把调用到的方法的指令直接植入当前方法中,如下代码:
public void bar(){
....
bar2();
....
}
private void bar2(){
//bar2;
}
上面代码编译后就变成类似下面的结构:
public void bar(){
....
//bar2
....
}
-
去虚拟化 去虚拟化是指在装载class文件后,进行类层次的分析,如发现类中的方法只提供一个实现类,那么对于调用了此方法的代码,也可进行方法内联;
-
冗余削除 冗余削除是指在编译时,根据运行时状况进行代码折叠或削除,例如一段这样的代码:
public void execute(){
if(isDebug){
log.debug("enter this method: execute");
}
//do something
}
如isDebug的值是false,在执行C1编译后,这段代码就变成类似下面的结构:
public void execute(){
//do something
}
Server compiler又称C2,较为重量级,它采用大量的传统编译优化技巧来进行优化,占用内存相对会多一些,适合于服务器端的应用;逃逸分析是C2进行很多优化的基础,逃逸分析是指根据运行状况来判断方法中的变量是否会被外部读取,如不会则认为此变量是逃逸的,基于逃逸分析C2在编译时会标量替换,栈上分配和同步消除等优化;
- 标量替换 就是用标量替换聚合量,例如下面这段代码:
Point point=new Point(1,2);
System.out.println("point.x="+point.x+";point.y"+point.y);
当point对象在后面的执行过程中未用到时,经过编译后,代码会变成类似下面的结构:
int x=1;
int y=2;
System.out.println("point.x="+x+";point.y"+y);
- 栈上分配 在上面的例子中,如果p没有逃逸,那么C2会选择在栈上直接创建Point对象实例,而不是在堆上;
-
同步削除 指如果发现同步的对象未逃逸,那也没有同步的必要了,在C2编译时会直接去掉同步,例如:
Point point=new Point(1,2);
synchronized(point) {
//do something;
}
经过分析如果发现point未逃逸,在编译后,代码就会变成下面的结构:
Point point = new Point(1,2);
//do something
Sun JDK之所以未选择在启动时即编译成机器码,有下面几个原因:
- 静态编译并不能根据程序的运行状况来优化执行的代码
- 解释执行比编译执行更节省内存
- 启动解释执行的启动速度比编译再启动更快
相关推荐
综上所述,Java的运行机制涉及到编译、执行、类加载等多个层面,每个环节都对Java程序的成功运行起着至关重要的作用。深入理解这些机制有助于开发者更好地掌握Java语言的特点,提高编程效率和代码质量。
Java 代码审计案例及修复 Java 代码审计是指对 Java 源代码进行安全审查和评估,以发现潜在的安全漏洞和风险。Java 代码审计案例及修复旨在提供一个 Java 代码审计的实践指南,涵盖了 Java 代码审计的基本概念、...
在某些情况下,开发者可能需要将已有的C++代码转换为Java代码,以便在Java平台上运行或利用Java的生态系统。 标题“C++代码转Java工具”暗示了一个软件或服务的存在,它的功能是自动化C++源代码到Java源代码的转换...
此外,如果Java代码中包含了一些特定于Java平台的API调用,这些部分在Pascal中可能需要替换为相应的函数或库。 总的来说,Java2Pas是一个方便的工具,能够帮助开发者跨越Java和Pascal之间的语言障碍,提高代码复用...
通过使用此工具,开发者可以对比Java源代码和Smali代码,加深对Android系统运行机制的理解。 7. **优化和调试**:在某些情况下,直接修改Smali代码可能比修改Java源代码更有效,尤其是在处理性能问题或处理特定的...
Java虚拟机运行机制 Java虚拟机(JVM)是一种用于计算设备的规范,可以用不同的方式(软件或硬件)加以实现。JVM包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 Java虚拟机是一个...
在“java代码学校代码”的主题下,我们可以深入探讨以下几个关键知识点: 1. **基础语法**:Java的基础包括变量、数据类型、运算符、控制结构(如if语句、for循环、while循环)、方法定义和调用等。理解这些概念是...
### Java程序的运行机制详细分析 #### 一、Java为何具备平台独立性 Java作为一种广泛使用的编程语言,其最大的特点之一就是平台独立性。这意味着编写的Java程序可以在任何支持Java虚拟机(JVM)的操作系统上运行而...
8. **用户界面**:为了方便用户,工具可能包含一个图形用户界面,允许用户上传C#代码文件,然后直接导出转换后的Java代码。 使用这样的工具,开发者可以减少手动转换代码的工作量,提高工作效率,同时减少由于人为...
在Java编程中,源代码通常以`.java`为扩展名,经过Java编译器的处理,会被转化为字节码(`.class`文件),然后由Java虚拟机执行。 Java源代码的知识点涵盖了多个方面: 1. **基本语法**:Java源代码遵循特定的语法...
Synchronized 代码块是 Java 中的一种同步机制,它可以指定获取某个对象的钥匙,然后在该对象上的某个代码块中执行同步操作。Synchronized 代码块可以指定用哪一把钥匙才能开这个屏风的锁,可以用本房的钥匙,也可以...
用户只需运行这个程序,然后提供C#代码文件作为输入,它就能生成对应的Java代码。这样的工具简化了代码转换的过程,但需要注意的是,自动转换可能无法处理所有复杂情况,如特定的C#特性或库调用,这些在Java中可能...
Java虚拟机(JVM)是一种能够执行Java字节码的虚拟机,它提供了一个平台无关的执行环境,使得Java程序可以在各种不同的硬件和操作系统上运行。JVM解释执行机制是Java虚拟机执行字节码的一种方式,其中解释器将Java...
一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
- Java的异常处理机制允许程序员捕获并处理运行时错误。初学者可能会在代码中看到try-catch-finally结构,学习如何优雅地处理可能出现的问题。 7. **编译与运行** - 初学者将学习如何使用JDK中的javac命令编译源...
这种运行方式意味着Java字节码在任何平台上都需要通过Java虚拟机(JVM)进行解释和执行。JVM充当了一个中间层,对所有的操作进行调度和审核,确保程序不会直接调用本地操作系统的方法或过程,从而增强了平台无关性和...
本设计提出了基于Java卡的可信代码装载机制,采用代码签名技术作为主要手段,以卡内的安全域(Security Domain)作为各个软件权威的安全策略执行者。该机制包含三个主要组件: 1. 代码签名模块:负责对代码进行签名...
通过深入理解Java的运行机制,我们可以有针对性地进行优化,确保程序在高负载下也能保持良好的运行状态。 目的 本计划的目标是: 1. 识别代码中可能导致性能下降的常见问题。 2. 提供优化建议,使代码更加高效。 3...
在Qt中,可以使用QProcess或其他I/O组件来启动JVM并传递参数,以执行Java代码。同时,可以使用信号和槽机制来协调C++和Java之间的事件处理。 为了在实际项目中实现这一功能,你可能需要考虑更多的细节,比如错误...