文章目录
JVM体系结构概览
- 灰色的:线程私有,占用内存很少,几乎可以忽略,没有垃圾回收机制
- 亮色: 所有线程共享,存在垃圾回收
类装载器ClassLoader
简介
- 负责加载class文件,class文件在文件开头有特定的文件标识(cafe babe)
- 将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构
- ClassLoader只负责加载class文件,至于是否可以运行由Execution Engine决定
装载器类型
虚拟机自带的加载器
- 启动类加载器(Bootstrap)C++写的
- 加载rt包,有Object类,String类等
- 扩展类加载器(Extension) java写的
- 加载ext包,是java后面新添加的包
- 应用程序类加载器(AppClassLoader),java也叫系统类加载器,加载当前应用的classpath的所有类
- 加载用户自定义的包
Object o = new Object();//自己写的类
System.out.println(o.getClass().getClassLoader().getParent().getParent());//报错,空指针
System.out.println(o.getClass().getClassLoader().getParent()); //报错,空指针
System.out.println(o.getClass().getClassLoader()); //null 是Bootstrap,C++写的
Class_Loader class_loader = new Class_Loader(); //自己写的类
System.out.println(class_loader.getClass().getClassLoader().getParent().getParent());//null
System.out.println(class_loader.getClass().getClassLoader().getParent());//sun.misc.Launcher$ExtClassLoader@28d93b30
System.out.println(class_loader.getClass().getClassLoader());//sun.misc.Launcher$AppClassLoader@14dad5dc
用户自定义加载器
- Java.lang.ClassLoader的子类
加载机制
- 双亲委派机制:当一个类收到了类加载器请求,加载器首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成(即会一直找到根父类Bootstrap),只有当父类中没有这个类时,它的子类才会依次加载(即你如果你定义了String类,最终加载出来的还是)
- 类加载过程
Native
Native Interface本地接口
本地接口的作用是融合不同的编程语言为java所用,初衷是融合C,C++。内存中专门开辟了一块区域,标记为native代码,具体做法是在Native Method Stack中登记native方法,在Execution Engine执行时加载native libraies
(目前该方法使用越来越少了,除非与硬件有关的应用)
Native Method Stack
它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时加载本地方法库
程序计数器(PC寄存器)
基本介绍
- 每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也就是即将要执行的指令代码),由引擎读取的下一条指令,是一个非常小的内存空间,几乎可以忽略不计
- 这块内存区域很小,它是当前线程所执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取吓一跳需要执行的字节码指令
- 如果执行的是一个Native方法,那么这个计数器是空的
- 用以完成分值、循环、跳转、异常处理、线程回复等基础功能。不会发生内存溢出错误
方法区
基本信息
- 供各个线程共享的运行时内存区域。它存储了每一个类的结构信息,例如运行时常量池、字段和方法数据、构造函数和普通方法的字节码内容。
- 上面讲的是规范,在不同虚拟机里头是现实不一样的,最典型的就是永久代和元空间(方法区 F = new 永久代)
- 实例变量存在堆内存中,和方法区无关
- static在方法区中、非static在堆中
存储内容
- 常量池
- 静态变量
- 类信息(Class)
- 静态引用变量(存的是堆对象的引用)