3.从0开始的手写java虚拟机 -运行时数据区

本文从0开始介绍了手写Java虚拟机的过程,详细讲解了运行时数据区,包括线程共享的堆和方法区,以及线程私有的程序计数器和虚拟机栈。在类加载过程中,解析类路径,创建类加载器,并进行了类的验证、准备和初始化,最终获取主入口main方法并开始执行。同时,文中还提及了关键的数据结构,如线程、栈帧、局部变量表和操作数栈。
摘要由CSDN通过智能技术生成

3.从0开始的手写java虚拟机 - 类加载过程实现

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
//MyObject.class

public class MyObject {
   
    public static int staticVar;
    public int instanceVar = 1;

    public MyObject() {
   
    }

    public static void main(String[] args) {
   
        int x = 12345;
        MyObject myObj = new MyObject();
        staticVar = x;
        int x = staticVar;
        if (myObj instanceof MyObject) {
   
            myObj = (MyObject)myObj;
            System.out.println(myObj.instanceVar);
            System.out.println(myObj.instanceVar + staticVar);
        }

    }
}
//运行命令
//liyuan.exe -Xjre D:\jre1.8 -cp E:\m2\mysql\mysql-connector-java\8.0.21\mysql-connector-java-8.0.21.jar;E:\ideaProjects\HandWritingJVM\lib\*;E:\ideaProjects\HandWritingJVM MyObject

3.0.基础知识

3.1.运行时数据区

3.1.1.线程共享

堆:存放对象数据;
方法区:存放类数据,包括字段和方法信息,方法的字节码,运行时常量池…

3.1.2.线程私有

程序计数器:
Java虚拟机栈:栈帧,保存方法执行的状态,包括局部变量表,操作数栈;

3.1.类加载过程

  1. 解析类路径,启动类路径,扩展类路径,用户类路径
  2. 新建类加载器并加载主类,设置其基本信息,如父类,接口信息
  3. 校验该主类
  4. 准备:(1)计算实例的字段所需要的插槽数
  5. 准备:(2)计算静态字段所需的插槽数
  6. 准备:(3)初始化静态以及fianl变量
  7. 获取main方法
  8. 开始执行
func startJVM(cmd *Cmd) {
   
	cp := classpath.Parse(cmd.XjreOption, cmd.cpOption)
	classLoader := heap.NewClassLoader(cp)
	fmt.Printf("classpath: %s class: %s args:%v\n", cmd.cpOption, cmd.class, cmd.args)
	className := strings.Replace(cmd.class, ".", "/", -1)
	mainClass := classLoader.LoadClass(className)
	mainMethod := mainClass.GetMainMethod()
	//classFile := loadClass(className, cp)
	//fmt.Println(classFile)
	if mainMethod != nil {
   
		interpret(mainMethod)
	} else {
   
		fmt.Println("Main method could not be found in class %s\n", cmd.class)
	}
}
3.1.1.解析类路径

1.从0开始的手写java虚拟机 - 读取类路径下的class文件

3.1.2.新建类加载器
//类加载器结构体
type ClassLoader struct {
   
	cp       *classpath.Classpath
	classMap map[string]*Class //loaded class
}

func NewClassLoader(cp *classpath.Classpath) *ClassLoader {
   
	return &ClassLoader{
   
		cp:       cp,
		classMap: make(map[string]*Class),
	}
}
//主要方法如下
//通过类名加载类
func (self *ClassLoader) LoadClass(name string) *Class {
   
	//若该类已被加载过,则直接从内存取出
	if class, ok := self.classMap[name]; ok {
   
		//该类已被加载
		return class
	}
	//否则从外存加载
	return self.loadNonArrayClass(name)
}

//从类路径下加载主类
func (self *ClassLoader) loadNonArrayClass(name string) *Class {
   
	//从路径下加载该类
	data, entry := self.readClass(name)
	class := self.defineClass(data)
	link(class)
	fmt.Printf("[Loaded %s from %s]\n", name, entry)
	return class
}


func (self *ClassLoader) readClass(name string) ([]byte, classpath.Entry) {
   
	data, entry, err := self.cp.ReadClass(name)
	if err != nil {
   
		panic("java.lang.ClassNotFoundException: " + name)
	}
	return data, entry
}

//解析成class格式
func (self *ClassLoader) defineClass(data []byte) *Class {
   
	//将加载的文件解析成class格式
	class := parseClass(data)
	//设置类加载器
	class.loader = self
	//解析父类
	resolveSuperClass(class)
	//解析接口
	resolveInterfaces(class)
	//缓存下来
	self.classMap[class.name] = class
	return class
}

func parseClass(data []byte) *Class {
   
	cf, err := classfile.Parse(data)
	if err != nil {
   
		panic("java.lang.ClassFormatError")
	}
	return newClass(cf)
}

//解析超类
func resolveSuperClass(class *Class) {
   
	if class.name != "java/lang/Object" {
   
		class.superClass = class.loader.LoadClass(class.superClassName)
	}
}

//解析接口
func resolveInterfaces(class *Class) {
   
	interfacesCount := len(class.interfaceNames)
	if interfacesCount > 0 {
   
		class.interfaces = make([]*Class, interfacesCount)
		for index, name := range class.interfaceNames {
   
			class.interfaces[index] = class.loader.LoadClass(name)
		}
	}
}
3.1.3.使用类加载器加载类并进行链接过程
//该方法同上
func (self *ClassLoader) LoadClass(name string) *
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值