Need help with zvm?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

tzh476
147 Stars 31 Forks 54 Commits 1 Opened issues

Description

Java 实现 JVM

Services available

!
?

Need anything else?

Contributors list

No Data

Java实现简易JVM

主要模块和样例:

1. 读取并解析class文件,如String、Thread等类(支持jdk8及以下)

部分类可能在demo运行时用到:

  • zvm\bytecode\java\lang\System.class
  • zvm\bytecode\java\io\PrintStream.class
  • zvm\bytecode\java\lang\Thread.class
  • zvm\bytecode\com\zvm\javaclass\integer\Table1.class(注解相关)
2. 取opcode,解释执行程序。循环运算,入栈出栈
  • 执行样例:
    public class GaussTest {
      public GaussTest() {
      }
      public static void main(String[] args) {
          int sum = 0;
          for(int i = 5; i <= 20; i += 10) {
              sum += i;
          }
          System.out.println(sum);
      }
    }

输出结果:

file path : GaussTest
20
3. 方法调用(静态方法、构造方法、实例方法(支持继承多态))
  • 静态递归方法执行样例(invokestatic):
    public class FibonacciTest {
      public static void main(String[] args) {
          long x = fibonacci(8);
          System.out.println(x);
      }
      private static long fibonacci(long n) {
          if (n <= 1) {
              return n;
          } else {
              return fibonacci(n - 1) + fibonacci(n - 2);
          }
      }
    }

输出结果:

file path : FibonacciTest
21
  • 构造方法调用(invokespecial)
    public class FibonacciTest {
      public static void main(String[] args) {
          long x = fibonacci(8);
          System.out.println(x);
      }
      private static long fibonacci(long n) {
          if (n <= 1) {
              return n;
          } else {
              return fibonacci(n - 1) + fibonacci(n - 2);
          }
      }
    }

输出结果:

file path : FibonacciTest
21
  • 调用实例方法,支持继承多态(invokevirtual)
    public class InvokeVirtualTest {
      public static void main(String[] args) {
          Vector2D v2 = new Vector2D(2.1, 2.2);
          Vector2D v3 = new Vector3D(3.1, 3.2, 3.3);
          v2.multiply(2);
          v3.multiply(3);
          System.out.println(v2.x);
          System.out.println(v2.y);
          System.out.println(v3.x);
          System.out.println(v3.y);
          System.out.println(((Vector3D)v3).z);
      }
    }

输出结果:

file path : ch07/InvokeVirtualTest
4.2
4.4
9.3
9.600000000000001
9.899999999999999
4. 数组
  • 一维int数组冒泡排序:

    public class BubbleSortTest {
      public static void main(String[] args) {
          int[] arr = {
              22, 84, 77, 11, 95,  9, 78, 56,
              36, 97, 65, 36, 10, 24 ,92, 48
          };
          //printArray(arr);
          bubbleSort(arr);
          //System.out.println(123456789);
          printArray(arr);
      }
      private static void bubbleSort(int[] arr) {
          boolean swapped = true;
          int j = 0;
          int tmp;
          while (swapped) {
              swapped = false;
              j++;
              for (int i = 0; i < arr.length - j; i++) {
                  if (arr[i] > arr[i + 1]) {
                      tmp = arr[i];
                      arr[i] = arr[i + 1];
                      arr[i + 1] = tmp;
                      swapped = true;
                  }
              }
          }
      }
      private static void printArray(int[] arr) {
          for (int i : arr) {
              System.out.println(i);
          }
      }
    }

    输出结果:

    file path : ch08/BubbleSortTest
    9
    10
    ...
  • 一维double数组冒泡排序

    public class DoubleBubbleSortTest {
      public static void main(String[] args) {
          double[] arr = {
              22.2, 84.4, 77.5, 11.2, 95.3,  9.2, 78.2, 56.2,
              36.1, 97.1, 65.1, 36.1, 10.3, 24.3 ,92.3, 48.3
          };
    
          //printArray(arr);
          bubbleSort(arr);
          //System.out.println(123456789);
          printArray(arr);
      }
      private static void bubbleSort(double[] arr) {
          boolean swapped = true;
          int j = 0;
          double tmp;
          while (swapped) {
              swapped = false;
              j++;
              for (int i = 0; i < arr.length - j; i++) {
                  if (arr[i] > arr[i + 1]) {
                      tmp = arr[i];
                      arr[i] = arr[i + 1];
                      arr[i + 1] = tmp;
                      swapped = true;
                  }
              }
          }
      }
      private static void printArray(double[] arr) {
          for (double i : arr) {
              System.out.println(i);
          }
      }
    }
    

输出结果:
```java
file path : ch08/DoubleBubbleSortTest
9.2
10.3
11.2
22.2
24.3
...
5. 字符串和字符串数组
  • 字符串加法,涉及类有java/lang/StringBuilder、java/lang/AbstractStringBuilder、java/lang/Math 、java/util/Arrays、java/io/FilterOutputStream、java/io/OutputStream、 java/io/PrintStream、java/lang/String:

    public class StringBuilderTest {
      public static void main(String[] args) {
          String hello = "hello,";
          String world = "world!";
          String str = hello + world;
          System.out.println(str);
      }
    }

    输出结果:

    file path : ch09/StringBuilderTest
    总内存:8912 分配:8完成 当前已使用:8
    总内存:8912 分配:12完成 当前已使用:20
    ...
    hello,world!
    ...
  • 字符串数组

    public class ArrayDemo {
      public static void main(String[] args) {
          int[] a1 = new int[10];       // newarray
          String[] a2 = new String[10]; // anewarray
          //int[][] a3 = new int[10][10]; // multianewarray
          int x = a1.length;            // arraylength
          a1[0] = 100;                  // iastore
          int y = a1[0];                // iaload
          a2[0] = "0abc";                // aastore
          String s = a2[0];             // aaload
          System.out.println( s);
          a2[1] = "1xxxxyyxyy";
          a2[2] = "2xxxxyyxyy";
    
          for(int i = 0; i < 3; i++){
              System.out.println(a2[i] + " stringbuilderTest");
          }
      }
    }

输出结果:

file path : ch09/ArrayDemo
总内存:8912 分配:40完成 当前已使用:40
...
0abc
总内存:8912 分配:8完成 当前已使用:104
总内存:8912 分配:20完成 当前已使用:124
...
0abc stringbuilderTest
总内存:8912 分配:8完成 当前已使用:364
总内存:8912 分配:32完成 当前已使用:396
...
1xxxxyyxyy stringbuilderTest
总内存:8912 分配:8完成 当前已使用:580
总内存:8912 分配:32完成 当前已使用:612
...
2xxxxyyxyy stringbuilderTest
...
6. 调用本地方法
  • 只实现了这个方法println,里面调用了arraycopy
    public class StringBuilderTest {
      public static void main(String[] args) {
          String hello = "hello,";
          String world = "world!";
          String str = hello + world;
          System.out.println(str);
      }
    }
    输出结果:
    file path : ch09/StringBuilderTest
    hello,world!
7. GC相关:简单实现了标记清除算法
  • 在zvm\src\main\java\com\zvm\memory\JavaHeap.java的HEAP_MAX_SIZE(此例中为32)的大小

    public class GCTest1 {
      private static final int SIZE = 3;
      public static void main(String[] args){
          test0();
          test1();
          test2();
      }
      private static void test0() {
          /*字符串会创建22 byte + 8byte的数组:8byte:为String对象,22byte为char[11]*/
          //System.out.println("test0 start");
          int[] arr = new int[SIZE];
          for (int i = 0; i < SIZE; i++){
              arr[i] = 100 + i;
          }
          //System.out.println("test0 start");
      }
    
      private static void test1() {
          //System.out.println("test1 start");
          int[] arr = new int[SIZE];
          for (int i = 0; i < SIZE; i++){
              arr[i] = 100 + i;
          }
          //System.out.println("test1 start");
      }
    
      private static void test2() {
          //System.out.println("test2 start");
          int[] arr = new int[SIZE];
          for (int i = 0; i < SIZE; i++){
              arr[i] = 100 + i;
          }
          //System.out.println("test2 start");
      }
    }

    输出结果:

    file path : gc/GCTest1
    总内存:32 分配:12完成 当前已使用:12
    总内存:32 分配:12完成 当前已使用:24
    总内存:32 已使用:24 当前需分配:12
    总内存:32 回收情况:24->0 当前需分配:12
    总内存:32 分配:12完成 当前已使用:12

其他 demo

1. 嵌套类
  • 执行样例: ```java /**
  1. 嵌套类:

*/ public class T0NestedClass { static class StaticClass{ public String staticClassKey = "staticClassVale"; public void test(){ System.out.println(staticClassKey); } }

/**
 * 普通内部类
 */
class GenaralClass{
    public String genaralClassKey = "genaralClassValue";
    public void test(){
        System.out.println(genaralClassKey);
    }
}

public static void main(String[] args){
    class LocalClass{
        public String localClassKey = "LocalClassValue";
        public void test(){
            System.out.println(localClassKey);
        }
    }

    AnonymousClass anonymousClass = new AnonymousClass(){
        public String anonymousClassKey = "anonymousClassValue";
        public void test(){
            System.out.println(anonymousClassKey);
        }
    };

    /*静态类测试*/
    StaticClass staticClass = new StaticClass();
    staticClass.test();

    /*普通内部类测试*/
    new T0NestedClass().generalClassTest();

    /*局部内部类测试*/
    LocalClass localClass = new LocalClass();
    localClass.test();

    /*匿名内部类测试*/
    anonymousClass.test();

}

public void generalClassTest(){
    GenaralClass genaralClass = new GenaralClass();
    genaralClass.test();
}

} class AnonymousClass{ public void test() { } }


输出结果:
```java
file path : nestedclass\T0NestedClass
总内存:32000 分配:4完成 当前已使用:4
...
staticClassVale
总内存:32000 分配:0完成 当前已使用:92
总内存:32000 分配:8完成 当前已使用:100
总内存:32000 分配:8完成 当前已使用:108
总内存:32000 分配:34完成 当前已使用:142
genaralClassValue
总内存:32000 分配:4完成 当前已使用:146
总内存:32000 分配:8完成 当前已使用:154
总内存:32000 分配:30完成 当前已使用:184
LocalClassValue
anonymousClassValue
2. 类的加载、链接、初始化
  • 执行样例:

    public class T1ClassLink {
      public static String value1 = "abc";
      public static final String finalValue = "zvm";
      public static String[] arr = new String[]{"arr0", "arr1", "dsafasfsdafd"};
      public static final String[] finalArr = new String[]{"final-arr0", "final-arr1", "final-dsafasfsdafd"};
      public String generalStr = "generalStr";
    
      public T1ClassLink() {
      }
    
      public static void main(String[] var0) {
          System.out.println(value1);
          System.out.println("zvm");
          System.out.println(arr[0]);
          System.out.println(finalArr[0]);
          System.out.println((new T1ClassLink()).generalStr);
      }
    }

输出结果:

file path : classlink\T1ClassLink
总内存:32000 分配:0完成 当前已使用:0
...
abc
总内存:32000 分配:8完成 当前已使用:210
总内存:32000 分配:6完成 当前已使用:216
zvm
总内存:32000 分配:8完成 当前已使用:224
...
arr0
总内存:32000 分配:8完成 当前已使用:426
...
final-arr0
总内存:32000 分配:4完成 当前已使用:624
...
generalStr

计划要实现

  • 反射
  • 多线程
  • 同步

怎么运行

1. 环境
  • 在Windows10,基于jdk8开发
  • 打印调试信息,可能需要maven引入Gson或fastjson
  • 支持解析jdk8及以下版本的类,解释执行demo
  • 经测试,demo支持在linux,jdk8中运行
2. IDEA运行
3. cmd运行
F:\projects\zvm>java -classpath E:\JAVA\Maven\com\alibaba\fastjson\1.2.62\fastjson-1.2.62.jar;E:\JAVA\Maven\com\google\code\gson\gson\2.8.5\gson-2.8.5.jar;F:\projects\zvm\target\classes com.zvm.JavaMain -cp F:\projects\zvm\bytecode gc.GCTest1

运行结果:

目录结构

1. 第一级目录
bytecode\  #编译后的字节文件
javaclass\ #测试demo的源文件
src\       #源代码

注:由jdk1.8.0_45\jre\lib\rt.jar中的java文件夹得到zvm\bytecode\java文件夹

2. 源代码目录
com\zvm
    basestruct\                 #读取字节码为内存中ClassFile时的基本数据结构
    classfile\                  #类解析相关
       attribute\               #属性表:jdk8中的23种属性
       constantpool\            #常量池:jdk8中10种常量类型
       ClassFile.java           #解析后的class文件
       cp_info.java             #ClassFile中的常量池表示
       field_info.java          #ClassFile中的字段表示
       IOUtils.java             #解析字节码的工具类
       method_info.java         #ClassFile中的方法表示
       ZvmClassLoader.java      #待重构
    draft\                      #草稿,无需理会
    gc\
       GC.java                  #GC类,目前只有标记清除算法
    instruction\                #指令实现(根据Java虚拟机规范分类建立子目录)
       arithmetic\              #运算指令
          arithmetic\           #算术运算
          bitwise\              #位运算符
          logic\                #逻辑运算符
          relation\             #关系运算符
          unary\                #一元运算符  
       controltransfer\         #控制转移 
       exception\               #抛出异常
       loadandstore\            #加载和存储
          constant\             #常量加载至操作数栈
          load\                 #局部变量表至操作数栈
          store\                #操作数栈到局部变量表
       methodinvocation\        #方法调用
       objectcreatemanipulate\  #对象创建和操作
       oprandstack\             #操作数栈操作
       synchronization\         #同步
       typeconversion\          #类型转换
       Opcode.java              #指令opcode
       Instruction.java         #所有指令都implements这个接口
    interpreter\                
       CallSite.java            #调用方法时的入口
       CodeUtils.java           #控制pc的工具类
       Descriptor.java          #方法调用时,表示返回数据和入参结构
       Interpreter.java         #取opcode并执行的类
       Ref.java                 #表示methodRef或fieldRef:含类名、描述符、方法名/字段名
    jnative\                    #实现本地方法
        NativeConstant.java     #调用相关常量
        NativeMethod.java       #所有本地方法都需要实现这个接口
        NativeUtils.java        #本地方法注册调用工具
        System.java             #实现System类中的本地方法
    memory\
       ArrayFields.java         #保存堆中的数组
       JavaHeap.java            #表示堆,对象和数组都分配在这
       MethodArea.java          #方法区
       ObjectFields.java        #表示堆中的对象
    runtime\                    #运行时数据
       struct\                  #一些基本数据结构
       JavaClass.java           #运行时表示:ClassFile的入口,加一些类的信息
       JavaFrame.java           #运行时表示:一个方法所用的帧
       JThread.java             #运行时表示:一个线程(目前未实现多线程)
       LocalVars.java           #运行时表示:帧中的局部变量表
       OperandStack.java        #运行时表示:帧中的操作数栈
       RunTimeEnv.java          #运行时的环境,包括JavaHeap、MethodMrea等
       StaticVars.java          #JavaClass中的静态字段分配内存
       ThreadStack.java         #线程栈:运行时,方法调用帧由底至上组成线程栈
       Vars.java                #供LocalVars、LocalVars、ObjectFields继承使用
    utils\
       TypeUtils.java           #类型转换工具类
    Cmd.java                    #解析命令行
    JavaMain.java               #启动入口类,含main方法
    ZVM.java                    #表示虚拟机

已实现指令(绝大部分实现了)

1. 加载(load)、存储(store)指令,将数据在局部变量表和操作数栈中来回传输
  • 局部变量表->操作数栈:dload,dload_n; iload,iload_n; lload,lload_n; aload,aload_n
  • 操作数栈->局部变量表:dstore,dstore_n; istore,istore_n; lstore,lstore_n; astore,astore_n
  • 常量到操作数栈: bipush,ldc,ldc_w,ldc2_w,iconst_n
2. 运算指令
  • 加法:iadd,ladd
  • 减法: lsub
  • 乘法: dmul
  • 自增: iinc
  • 比较: lcmp
3. 类型转换指令
  • 待实现
4. 对象创建和操作
  • 创建实例: new
  • 创建数组:anewarray,newarray
  • 访问类或实例字段:getstatic,getfield,putfield
  • 将一个数组元素加载到操作数栈:iaload,laload,faload,daload,aaload
  • 将一个操作数栈的值存储到数组中:iastore, lastore, fastore, dastore, aastore
  • 获得数组的长度:arraylength
  • 检查类实例类型的指令:instanceof、checkcast待实现
5. 操作数栈管理
  • pop, pop2, dup, dup2, dup_x1, dup2_x1, dup_x2, dup2_x2, swap
6. 控制转移
  • 条件分支:ifeq, ifne, iflt, ifle, ifgt, ifge, ifnull, ifnonnull, if_icmpeq,
     if_icmpne, if_icmplt, if_icmple, if_icmpgt if_icmpge, if_acmpeq, if_acmpne
  • 复合条件分支:tableswitch, lookupswitch待实现
  • 无条件分支: goto, goto_w, jsr, jsr_w, ret.
7. 方法调用和返回
  • invokevirtual: 调用对象实例方法,根据对象实际类型分派
  • invokespecial:特殊处理的实例方法:实例初始化方法,父类方法
  • invokestatic:调用类方法
  • invokeinterface:待实现
  • 返回指令: ireturn(used to return values of type boolean , byte , char , short , or int ), lreturn, freturn, dreturn, and areturn
8. 抛出异常
  • 待实现
9. 同步
  • 待实现

wiki

引用和参考

1. 文档、书籍参考
  • Java 虚拟机规范
  • 《自己动手写 Java 虚拟机》
  • Java虚拟机规范(Java se7)中文版
  • Java虚拟机规范(Java se8)中文版
  • 周志明的《深入理解 Java 虚拟机》
2. 代码参考
3. 工具

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.