在C里面我们想执行一段自己编写的机器指令的方法大概如下
typedefvoid(*FUNC)(int);
char*str=yourcode;
FUNCf=(FUNC)str;
(*f)();
也就是说我们完全可以做一个工具从一个文件中读入指令然后将这些指令运行起来上面代码中编好的机器指令当然指的是能在CPU上运行的如果这里我还实现了一个翻译机器从自己定义的格式指令翻译到CPU指令那么就可以执行根据自定义格式的代码了那么上面这段代码是不是相当于最简单的一个虚拟机了?下面来看JVM的总体结构
ClassLoader的作用是装载能被JVM识别的指令(当然不只是从磁盘文件或内存去装载)那么我们先了解一下该格式
魔数以及版本就不说了(满大街的文件格式都是这个东西)接着的便是常量池其中无非是两种东西
Exceptions则非常简单
LineNumberTable保存了字节码和源码之间的关系结构如下
LocalVariableTable描述了栈帧中局部变量表的变量和源代码中定义的变量之间的关系结构如下
SourceFile指明了生成该Class文件的Java源码文件名(比如在一个Java文件中申明了很多类的时候会生成很多Class文件)结构如下
Deprecated和Synthetic属性只存在有和没有的区别
这样默认的类会是有Application ClassLoader去加载类然后如果发现要使用新的类型的时候则会递归地使用Application ClassLoader去加载(在前面的加载过程中提到)这样只有在自己的程序中能使用自己编写的ClassLoader去加载类并且这个被加载的类是不能被别人使用的
双亲委派模式不是一个强制性的约束而是Java设计者推荐给开发者的类加载实现方式双亲委派模式出现过的次破坏
加载完完成后接下来就要看程序是怎么运行的栈帧是用于支持虚拟机进行方法调用和执行帧的意思就是一个单位在调用其他方法的时候会向栈中压入栈帧结构如下
在Class文件编译完成之后在运行的时候需要多少个局部变量就已经确定(在前面Class文件中也已经看到过了)那么这里需要注意这个特性可能会引发GC(具体如何引发就不在这里细说了)在栈中总是底层的栈去调用高层的栈(并且一定的相邻的)那么他们在参数传递(返回结果)的时往往是通过将其压入操作数栈有些虚拟机为了提高这部分的效率使得相邻栈帧纠缠在一起
那么我们接下来要去看是方法是如何执行的第一个问题就是执行哪个方法?在面向过程的编程中似乎不存在在个问题但是在Java OR C++中这都是比较蛋疼的一个问题原因就是平时不会这么用但是你必须去搞明白= =