class文件被load进内存,同时生成一个Class类的对象,可以用这个Class对象指向这块内容。(class类的对象不是new出来的,是hotspot中C++代码load出来的)
内存分区,存常量,逻辑上是 method Area 方法区
1.8之前叫 Perm Generation 永久代
1.8之后叫 Meta Space
这两个都是指方法区
1. loading class文件加载到内存
2. linking
1. Verification 校验该文件是否符合class文件标准
2. Preparation 把class的静态变量 赋 默认值
3. Resolution 常量池里的符号引用转换成实际能直接访问到的地址
3. Initializing 静态变量赋值为初始值
Class类可以用来解析
class文件的二进制码
不同的类加载器负责加载不同的class
String.class.getClassLoader ( )
!!! 加载器直接不是继承关系,只是层次关系
加载核心包;类加载器的范围路径:sun.boot.class.path
ClassLoader的ClassLoader是Bootstrap加载器,最顶级的加载器 打印为 null
Bootstrap加载器 负责 加载 JDK中最核心的 jar
如 runtime.jar
charset,jar 等等
是C++实现的
Bootstrap 引导的意思
打印为 ExtClassLoader
加载扩展包;
类加载器的范围路径:java.ext.dirs
加载扩展jar包
jre/lib/ext/*.jar
ext目录下的jar 都是扩展包
或 由 -Djava,ext,dirs指定
打印为 AppLoader
加载我们自己写的 Java 类;
类加载器的范围路径:java.class.path
加载 classpath 指定的内容
我们自己写的 java 文件都是位于classpath下
由 App 加载器加载
APP extend Ext
APP加载器的父类是Ext加载器
APP加载器的逻辑上的上一级加载器也是Ext加载器
但APP加载器的加载器是null
而Ext没有parent
使用ClassLoader的loadClass(“类路径”)就能把类加载进内存,返回Class类的对象
Class clazz=Student.class.getClassLoader().loadClass(“com.soft.Student”);
继承ClassLoader,重写findClass方法
使用字节流把,class文件load加载到内存
再使用 defineClass(name,字节流,0,bytes.length) 截取字节流中[0,bytes.lengrh]位置的字节转化为Class类的对象
// class对象通过反射生成对象,调用方法
Hello h =(Hello)class.newInstance()
h.m()
======================
通过自定义ClassLoader可以对class加密
把生成的class文件 01值 对某个种子值seed 进行异或 ^ 加密
再seed异或一下就是解密
int seed=0B10110110
随便一个种子值都行
JVM是按需动态加载采用双亲委派机制
.class 被load进内存的过程
自定义了类加载器,则先用自定义的类加载器,它内部维护一个缓存,记录这个class是否被加载进来了,如果没加载进来,就回去问App加载器是否加载了,加载就返回结果,
否则就再往上问,问Extension加载器加载了吗,如果有就返回结果,
如果没有就继续往上问Bootstrap加载了吗,如果有就返回,没有,就让 Extension加载器加载,如果找到就加载,如果没有找到,就让App加载器去加载,如果找到就加载,
如果没有,就让custom classloader加载
还是没找到,就报classNotFound异常
Bootstrap
Extension
App
Custom ClassLoader
每个加载器都有自己的缓存
先自底向上检查 该类是否已经加载 parent 方向
再自顶向下 进行实际查找和加载child方向
主要是为了安全。次要问题是加载过了,浪费资源;
如果没有这个机制,可以随便把自己写的类Load进内存,会有安全问题,比如自己写一个类叫 java.lang.String ,把它load进内存,会破坏原有的API
父加载器不是 “类加载器的加载器”,也不是“类加载器的父类加载器” ,只是上一层次的更高级的加载器;
双亲委派是一个孩子向父亲的方向,然后父亲再向孩子方向委派的过程
重写loadClass方法 ,而不是重写findclass
什么时候需要打破双亲委派
JDK1.2之前自定义ClassLoader都必须重写loadClass()
设置自己线程的classLoader()
热启动、热部署,为了加载同一类库的不同版本(使用两个同名的类)
编译成本地代码,类似.exe
混合使用 解释器 + 热点代码编译
起始阶段采用解释执行
==========
热点代码阶段
多次被调用的方法(方法计数器:监测方法执行频率)
多次被调用的循环 (循环计数器:监测循环执行频率)
进行编译
==========
-Xmined 模式为混合模式。开始解释执行,启动速度较快,对热点代码进行检测和编译
-Xint 使用纯解释模式,启动很快执行稍慢
-Xcomp 使用纯编译模式,执行很快,启动很慢
检测热点代码
-XX:CompileThreshold=10000
不是
java的三种类
系统类 比如 rt.jar
拓展类 比如 ext/*.jar
自己写的类
加载的时候是先加载核心类,再拓展类,最后自己的类
按需加载,Student s=new Student()被执行了,会被加载
Student s2=null就不会加载
初始化子类的时候,父类首先被初始化
虚拟机启动时,被执行的主类必须初始化
new 、getstatic、putstatic、invokestatic指令时该类必须初始化
对类进行反射调用时必须初始化
动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstaticREF_putstaticREF_invokestatic的方法句柄时,该类必须初始化