学习Java字节码有助于理解Java内存结构,加深对JVM的理解。
首先需要知道JVM内存由堆、栈、方法区、本地方法栈组成。
堆中存放JVM生命周期里所有的类的实例。
栈中存放函数中的基础类型局部变量、函数中实例变量的引用。
方法区存放Class、Method的信息以及Static的变量。
本地方法栈存放调用本地方法时用到的变量。
JVM为每个线程都分配了一个方法栈,方法栈包含不同方法的栈帧,每个方法都有一个栈帧,当前方法的栈帧称为当前栈帧,栈帧由局部变量区和操作数栈组成,所有线程共享堆中的数据。
下面以一个简单的Java程序HelloWorld.java为例,介绍一下Java方法调用时的内存结构。
源代码
Java代码
public class HelloWorld {
private String myWorld;
public HelloWorld(String world) {
this.myWorld = world;
}
public String getMyWorld() {
return myWorld;
}
public void setMyWorld(String myWorld) {
this.myWorld = myWorld;
}
public boolean isNull(){
if(this.myWorld==null){
return true;
}else{
return false;
}
}
public static void main(String[]args){
HelloWorld myWorld = new HelloWorld("smallWorld");
boolean isNull = false;
myWorld.setMyWorld("bigWorld");
isNull = myWorld.isNull();
}
}
public class HelloWorld {
private String myWorld;
public HelloWorld(String world) {
this.myWorld = world;
}
public String getMyWorld() {
return myWorld;
}
public void setMyWorld(String myWorld) {
this.myWorld = myWorld;
}
public boolean isNull(){
if(this.myWorld==null){
return true;
}else{
return false;
}
}
public static void main(String[]args){
HelloWorld myWorld = new HelloWorld("smallWorld");
boolean isNull = false;
myWorld.setMyWorld("bigWorld");
isNull = myWorld.isNull();
}
}
Javap -C HelloWorld
字节码:
Java代码
Compiled from "HelloWorld.java"
public class com.sitech.core.HelloWorld extends java.lang.Object{
public com.sitech.core.HelloWorld(java.lang.String);
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #13; //Field myWorld:Ljava/lang/String;
9: return
public java.lang.String getMyWorld();
Code:
0: aload_0
1: getfield #13; //Field myWorld:Ljava/lang/String;
4: areturn
public void setMyWorld(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #13; //Field myWorld:Ljava/lang/String;
5: return
public boolean isNull();
Code:
0: aload_0
1: getfield #13; //Field myWorld:Ljava/lang/String;
4: ifnonnull 9
7: iconst_1
8: ireturn
9: iconst_0
10: ireturn
public static void main(java.lang.String[]);
Code:
0: new #1; //class HelloWorld
3: dup
4: ldc #27; //String smallWorld
6: invokespecial #29; //Method "<init>":(Ljava/lang/String;)V
9: astore_1
10: iconst_0
11: istore_2
12: aload_1
13: ldc #31; //String bigWorld
15: invokevirtual #33; //Method setMyWorld:(Ljava/lang/String;)V
18: aload_1
19: invokevirtual #35; //Method isNull:()Z
22: istore_2
23: return
}
Compiled from "HelloWorld.java"
public class com.sitech.core.HelloWorld extends java.lang.Object{
public com.sitech.core.HelloWorld(java.lang.String);
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #13; //Field myWorld:Ljava/lang/String;
9: return
public java.lang.String getMyWorld();
Code:
0: aload_0
1: getfield #13; //Field myWorld:Ljava/lang/String;
4: areturn
public void setMyWorld(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #13; //Field myWorld:Ljava/lang/String;
5: return
public boolean isNull();
Code:
0: aload_0
1: getfield #13; //Field myWorld:Ljava/lang/String;
4: ifnonnull 9
7: iconst_1
8: ireturn
9: iconst_0
10: ireturn
public static void main(java.lang.String[]);
Code:
0: new #1; //class HelloWorld
3: dup
4: ldc #27; //String smallWorld
6: invokespecial #29; //Method "<init>":(Ljava/lang/String;)V
9: astore_1
10: iconst_0
11: istore_2
12: aload_1
13: ldc #31; //String bigWorld
15: invokevirtual #33; //Method setMyWorld:(Ljava/lang/String;)V
18: aload_1
19: invokevirtual #35; //Method isNull:()Z
22: istore_2
23: return
}
重点看一下main方法中调用isNull方法的操作:
Java代码
public static void main(java.lang.String[]);
Code:
0: new //在堆中分配内存,返回对象引用,压入操作数栈
3: dup //复制引用,压入栈
4: ldc //将常量池中的常量smallWorld压入栈
//JVM会将main方法操作数栈中的变量弹出放入构造函数的
//局部变量区
6: invokespecial //调用构造函数,弹出对象引用和参数
//调用结束后,JVM会将构造函数返回值压入main方法操作数栈
9: astore_1 //将对象引用弹出,存储在main方法局部变量1的位置
10: iconst_0 //将false值压栈
11: istore_2 //弹出false并存储于main方法局部变量2的位置
12: aload_1 //将对象引用压栈
13: ldc //将将常量池中的常量bigWorld压入栈
//JVM会将main方法操作数栈中的变量弹出放入实例方法
//的局部变量区
15: invokevirtual //调用实例函数setMyWorld,弹出对象引用和参数
18: aload_1 //将对象引用存储在main方法局部变量1的位置
//JVM会将main方法操作数栈中的变量弹出放入实例方法的
//局部变量区
19: invokevirtual //调用实例函数isNull,弹出对象引用和参数
//调用结束后,JVM会将构造函数返回值压入main方法操作数栈
22: istore_2 //弹出true并存储于main方法局部变量2的位置
23: return
public static void main(java.lang.String[]);
Code:
0: new //在堆中分配内存,返回对象引用,压入操作数栈
3: dup //复制引用,压入栈
4: ldc //将常量池中的常量smallWorld压入栈
//JVM会将main方法操作数栈中的变量弹出放入构造函数的
//局部变量区
6: invokespecial //调用构造函数,弹出对象引用和参数
//调用结束后,JVM会将构造函数返回值压入main方法操作数栈
9: astore_1 //将对象引用弹出,存储在main方法局部变量1的位置
10: iconst_0 //将false值压栈
11: istore_2 //弹出false并存储于main方法局部变量2的位置
12: aload_1 //将对象引用压栈
13: ldc //将将常量池中的常量bigWorld压入栈
//JVM会将main方法操作数栈中的变量弹出放入实例方法
//的局部变量区
15: invokevirtual //调用实例函数setMyWorld,弹出对象引用和参数
18: aload_1 //将对象引用存储在main方法局部变量1的位置
//JVM会将main方法操作数栈中的变量弹出放入实例方法的
//局部变量区
19: invokevirtual //调用实例函数isNull,弹出对象引用和参数
//调用结束后,JVM会将构造函数返回值压入main方法操作数栈
22: istore_2 //弹出true并存储于main方法局部变量2的位置
23: return
再来看看isNull方法:
Java代码
public boolean isNull();
Code:
0: aload_0 //将局部变量区的对象引用参数压栈
1: getfield //访问堆区的类实例
4: ifnonnull //是否为空
7: iconst_1 //如果是true,将1压入操作数栈
8: ireturn
9: iconst_0 //如果是false,将0压入操作数栈
10: ireturn
public boolean isNull();
Code:
0: aload_0 //将局部变量区的对象引用参数压栈
1: getfield //访问堆区的类实例
4: ifnonnull //是否为空
7: iconst_1 //如果是true,将1压入操作数栈
8: ireturn
9: iconst_0 //如果是false,将0压入操作数栈
10: ireturn
方法调用结束后,JVM会将isNull操作数栈中的返回值压入main方法的操作数栈中。
分享到:
相关推荐
java反射机制描述及Method.invoke解释
主要介绍了Java反射机制及Method.invoke详解,本文讲解了JAVA反射机制、得到某个对象的属性、得到某个类的静态属性、执行某对象的方法、执行某个类的静态方法等内容,需要的朋友可以参考下
java反射机制详解及Method.invoke解释.pdf
主要介绍了详解Java中Method的Invoke方法,需要的朋友可以参考下
主要介绍了Java Method类及invoke方法原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
invokeStaticMethod.java 调用静态方法示例 localVariable.java 演示局部变量 localVSmember.java 局部变量与成员变量同名问题示例 onlyTest.java 对象传值示例 otherClass.java 从类的外部访问对象的成员 ...
这是一个基于spingBoot的项目,通过此项目可以实现对fabric...5,执行QueryChaincode.java,或是InvokeChaincode.java 6,启动web服务:执行DemoApplication.java 详细教程见: https://mp.csdn.net/postedit/88354838
java reflect Method getDeclaredMethod invoke getConstructor
How to invoke Java web service in ASP
详细教程请打开https://blog.csdn.net/qq_27348837/article/details/88354838 这是一个基于spingBoot的项目,通过此项目可以实现对fabric网络的简单调用,并且可以启动一个fabric网路的服务,直接在网页上调用.
3.4.3 第三趟:字节码验证 3.4.4 第四趟:符号引用的验证 3.4.5 二进制兼容 3.5 java虚拟机中内置的安全特性 3.6 安全管理器和java api 3.7 代码签名和认证 3.8 一个代码签名示例 3.9 策略 3.10...
这个文章是某位高人所写,委托及其异步运用写得很精辟(老有转c#的同学问这个,其实他们不知道这玩意跟指针没多大区别,只是微软把他封了一层又一层而已,看明白了用就行了).不过这个异步是上古写法了,现在都用async~...
Invoking a Java Method Invoking a Native Method Other Forms of Method Invocation The invokespecial instruction invokespecial and () invokespecial and Private Methods invokespecial and super The...
本程序实现Invoke反射,内置说明txt文档,可以参考
以下的问题是由于java的堆内存已满,需要java运行时加大java的堆内存空间 2019-10-09 18:02:32.858 [http-nio-8239-exec-6] ERROR c.a.b.c.exceptionHandler.CodeBaseExceptionHandler:69 - Handler dispatch failed...
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("begin " + method.getName()); Object retval = method....
How to invoke Java web service in ASP.net using C#.zip
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null;} public Statement createStatement() throws SQLException { return null;} public PreparedStatement ...
3.4.3 第三趟:字节码验证 3.4.4 第四趟:符号引用的验证 3.4.5 二进制兼容 3.5 Java虚拟机中内置的安全特性 3.6 安全管理器和Java API 3.7 代码签名和认证 3.8 一个代码签名示例 3.9 策略 3.10...
然后再在 Java 中载进这个适配器 dll/so ,再编写 Java?? native 函数作为 dll 中函数的代理。 经过 2 个繁琐的步骤才能在 Java 中调用本地代码。 因此,很少有 Java 程序员愿意编写调用 dll/.so 库中的原生函数的 ...