JVM 基本概念

118 阅读3分钟

Java语言的跨平台特性

image.png

image.png

java的五大模块

  • ClassFile 字节码文件
  • 类装载子系统
  • 运行时数据区
  • 执行引擎(JIT编译器和GC垃圾回收器)
  • 本地方法栈

image.png

Class File 官方参照 docs.oracle.com/javase/spec…

  • Class字节码文件时JVM识别的一种文件,里面地址都是逻辑地址。最后需要运行在操作系统中,由于操作系统只能识别真实的物理地址。此时需要动态链接,即运行时动态的绑定对象、对象地址。
  • Class字节码文件是一组以8位字节为基础单位的二进制流,各个数据项严格按照顺序紧凑地排列在Class文件中,中间没有添加任何分隔符,整个Class文件存储的内容几乎全部是程序运行所必须数据。
  • Class字节码文件只有两种数据类型:无符号数(u)和表(info

javap -verbose class类名可以看class文件

image.png

以下是官方的Class File 文件结构 image.png

javac 命令编译生成.class文件 用编辑器以16进制方式打开

image.png

以下是部分解析示例 u4 magic ca fe ba be 魔法数表示当前文件是class文件 二进制值 u2 minor_version 00 00 class文件副版本号 0 u2 major_version 00 34 class文件主版本号 52 u2 constant_pool_count 00 25 常量池计数 37 cp_info constant_pool[constant_pool_count - 1] 常量池有36个cp_info结构

以下是官方给出的cp_info结构 image.png 解析第一个 cp_info
无符号数 类型 十六进制 十进制 对应表类型 u1 tag 0a 10 CONSTANT_Methodref u1 info[]

CONSTANT_Methodref的结构 image.png

CONSTANT_Methodref_info {
    u1 tag;                      //上面的引用 tag类型的u1 无需解释
    u2 class_index;
    u2 name_and_type_index;
}

常量池中第一个变量 u2 class_index 00 05 05 类的索引 u2 name_and_type_index; 00 0e 24 名称及类型索引


类装载子系统 Class Loader SubSystem

classfile 通过 class loader 加载到 runtime data area 的过程

image.png

链接分为三个阶段

  • 验证:验证是否符合虚拟机规范,是否会对jvm造成伤害或侵入性
  • 准备:为类加载内存,对类变量进行初始化
  • 解析:对虚拟机中常量池的符号引用变为直接引用

最终通过双亲委派机制加载到虚拟机内存当中

image.png

ClassLoader 类的 loadClass 方法

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

自定义类加载器

public class SelfClassLoader extends ClassLoader{
    private String path;
    private String clName;

    public SelfClassLoader(String path, String clName) {
        this.path = path;
        this.clName = clName;
    }

    public SelfClassLoader() {

    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] b = loadClassData(name);
        return defineClass(name,b,0,b.length);//调用继承类classLoder的defineClass方法定义类
    }

    private byte[] loadClassData(String name) {
        name = path+name.replace(".","\")+".class";
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = new FileInputStream(new File(name));
            out = new ByteArrayOutputStream();
            int i = 0;
            while ((i=in.read())!=-1){
                out.write(i);
            }
        }catch (Exception e){

        }finally {

        }
        return out.toByteArray();
    }
}

ClassLoader的 defineClass 方法

protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                     ProtectionDomain protectionDomain)
    throws ClassFormatError
{
    protectionDomain = preDefineClass(name, protectionDomain);
    String source = defineClassSourceLocation(protectionDomain);
    Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
    postDefineClass(c, protectionDomain);
    return c;
}