第6章 方法区 运行时常量池 类加载器

对象Object
里面有

Object{
  Class class;//所属的类
  Slot[] slots;//实例变量
}

方法区

运行时数据区的一块逻辑区域,由多个线程共享。
主要存放从class文件获取的类信息,类变量也存放在方法区中。
当Java虚拟机第一次使用某个类时,它会搜索类路径,找到相应的class文件,然后读取并解析class文件,把相关信息放进方法区。
至于方法区到底位于何处,是固定大小还是动态调整,是否参与垃圾回收,以及如何在方法区内存放类数据等,Java虚拟机规范并没有明确规定。

我放在ClassLoader里面

ClassLoader

public class MyClassLoader  {
    //依赖Classpath来搜索和读取class文件
    private Classpath classpath;

  //方法区 key是类的完全限定名
    private Map<String, Class> classInfoMap=new HashMap<>();
  
  
    public Class loadClass(String className){

        Class class = classInfoMap.get(className);

        if (class==null){
            classInfo=  ......
            classInfoMap.put(className,class);
        }
        return class;
    }
}

类的加载大致可以分为3个步骤:

  • 1.找到class文件并把数据读取到内存;
byte[] data;
 try {
  data = classpath.readClass(name);
} catch (Exception e) {
   e.printStackTrace();
   throw new RuntimeException("java.lang,ClassNotFoundException");
}
  • 2.解析class文件,生成虚拟机可以使用的类数据,并放入方法区;
    JClass classInfo = defineClass(data);
 private JClass defineClass(byte[] data)  {

        //byte[] -> classFile ->class
        JClass jClass = parseClass(data);
//并把其父类和接口也加载
       jClass.interfaces = resolveInterfaces(jClass.getInterfaceNames());
        jClass.superClass = resolveSuperClass(jClass.getSuperClassName());
//放入方法区
        classInfoMap.put(jClass.getName(),jClass);
        return jClass;
    }
  • 3.链接:验证和准备
 link(Class class ) {
  verify(class)
  prepare(class)
}
prepare(JClass classInfo) {

//数实例field ,给每个实例field 编号 set一个slotId,总数存class
        calcInstanceFieldSlotId(class);
//同上,这次是static Field,在class存一个这个数量的数组Object[] staticVars;
        calcStaticFieldSlotId(class);

//给final static的field赋值, 
//这些field的属性里面有常量池index是初值,
// 按其slotId放入类的staticVars
        allocAndInitStaticVars(class);
    }

类信息

JClass {

///////////////////////////////////////////直接copy来classFile
    @Getter(AccessLevel.NONE)
    private int accessFlags;// uint16 类的访问标志

    //完全限定名,具有java/lang/Object的形式
    private  String name;// thisClassName
    private  String superClassName;
    private  String[] interfaceNames;
    private RuntimeConstantPool runtimeConstantPool;//存放运行时常量池指针
    private Field[] fields;
    private Method[] methods;

/////////////////////////////////////////////////////////类加载时加工填充的
    public MyClassLoader classLoader;//加载时保留加载器引用
    public  JClass superClass;
    public  JClass[] interfaces;
    public int instanceSlotCount;
    public int staticSlotCount;
    public   Object[] staticVars;
}

对象

{
   JClass jClass;//所属的类
    Object[] slots;//实例field的值
}

Field

{
//类成员都有的部分
    protected     int accessFlags ;//classFile复制
    protected    String  name;//classFile复制
    public     String  descriptor;//classFile复制

    protected JClass jClass;//所属的类

    int constValueIndex ;//classFile得 在属性里 字段的初始值index

//static是类的staticVars的id  实例field是对象里面slots的id
     private   int slotId          ;//类加载时计算
}

Method

{
//类成员都有的部分
    protected     int accessFlags ;//classFile复制
    protected    String  name;//classFile复制
    public     String  descriptor;//classFile复制

    protected JClass jClass;//所属的类

//来自Code的属性
  private int maxStack ;
  private int maxLocals ;
  private   byte[]  code ;
}

运行时常量池

用classFile里的常量池 转的 index不变 没有就空着

classFile里的常量池 运行时常量池
数字(i l f d) 原样
UTF8
STRING(引用UTF8) 字符串
ClASS(引用UTF8) 类引用(类名,使用类[能拿类加载器])
NAME_AND_TYPE(引用UTF8)
FIELD_REF(引用ClASS,NAME_AND_TYPE) field引用(类引用,名,描述)
METHOD_REF(引用ClASS,NAME_AND_TYPE) method引用(类引用,名,描述)
INTERFACE_METHOD_REF(引用ClASS,NAME_AND_TYPE) method引用(类引用,名,描述)

classFile里的常量池有所属类的引用 , 每个常量都有对常量池本身的引用

类和对象相关指令

new


class=frame.method.class.runtimeConstantPool(操作数index);
 newObject={
    class
     slot[class.instanceSlotCount]//instanceSlotCount是类加载时按实例field数出来的
};
  frame.operandStack.push(newObject);

PutStatic

field=frame.method.class.runtimeConstantsPool[指令操作数index]
field.class.staticVars[field.slotId]

GetStatic

field=frame.method.class.runtimeConstantsPool[指令操作数index]
frame.operandStack.push(field.class.staticVars[field.slotId])

Putfield

 stack=frame.operandStack;
 val=stack.pop;
 object=stack.pop;
 field=frame.method.class.runtimeConstantsPool[指令操作数index];
 object.slot[field.slotId]=val;

Putfield

field=frame.method.class.runtimeConstantsPool[指令操作数index];
 stack=frame.operandStack;
object=stack.pop;
stack.push(object.slot[field.slotId]);

Instanceof

 class=frame.method.class.runtimeConstantPool(操作数index);
 stack=frame.operandStack;
 object=stack.pop;
 if(object.class isInstanceOf class){
    stack.push(1);
 }else{
   stack.push(0);
 }

Checkcast

object=stack.pop()
 stack.push(object);
 class=frame.method.class.runtimeConstantPool(操作数index);
 
 if(!object.class isInstanceOf class){
    throw new ClassCastException();
 }

用于


if (xxx instanceof ClassYYY) {//Instanceof
        yyy = (ClassYYY) xxx;//Checkcast
// use yyy
 }

Ldc

Object constant = frame.method().class().runtimeConstantPool[index]
operandStack.push(constant);

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,535评论 19 139
  • 字节码查看工具:WinHex 前言 Java虚拟机实现语言无关性的基石就是Class文件Java虚拟机提供的语言无...
    zlcook阅读 7,252评论 4 18
  • 1.流程 创建 HelloWorld.java代码如下package jvm; /** * @author ...
    RunAlgorithm阅读 1,413评论 4 6
  • 喜欢上摇滚,不单只是喜欢它那种震撼人心的力量呐喊,更加喜欢它特有的魅力-简单,真诚。 作为一名90后,受益前辈们的...
    天水清波阅读 908评论 0 0
  • 美国硅谷出了一个吊炸天的科技狂人,他的名字叫Elon Musk--埃隆·马斯克。为何说他是科技狂人呢?那么我们来看...
    岱挚阅读 670评论 0 1

友情链接更多精彩内容