共勉互学,如有误区请指出:
一:jvm虚拟机加载我们class,需要依靠类加载器。什么是类加载器,其实就是一个对象,这个对象什么时候创建的,简单指出就是操作系统调用底层文件jvm.dll文件创建而出(c++s实现),一共有三种类加载器,引导类加载器,扩展类,应用类。
那么问题来了,搞这么多加载器干嘛,个人理解为了隔离和规定,因为他每个加载器只加载对应的路径的.class文件
引导类:JRE的lib目录下的核心类库
扩展类:JRE的lib目录下的ext扩展目录中的
应用类:自己写的类
介绍先类的加载过程:
首先需要知道一点,每个类只会被加载一次,如果查询到了相同的全限定名的类被加载了就不会在被加载了,如果没被加载就需要看是否有父加载器,让其父类先加载,父类找不到再由自己加载findclass(双亲委派机制)。还有一点就是只有使用的时候才会被加载,不然一上来就把所有的类给加载,完了生成所有的类对象放入内存堆中,摸着脚板想也不可能那么傻,内存很珍贵的。
加载的过程分为:
加载:就是将硬盘上的class文件加载到内存
校验:你说加载就加载吗,虚拟机看不懂class文件好嘛,我要转为字节码,咖啡baby开头校验准确性。
准备:给类的静态变量分配内存,并赋予默认值(独一无二只给静态变量分配,所以也可以看出,静态变量只有一份,会有线程安全问题,个位大佬莫要再程序中乱定义静态变量,农作农贷)
解析:此处就是什么符号引用转为直接应用,个人理解就是解析字节码类容
初始化:你都给静态变量分配内存了,还不赶紧给我赋个默认值,完了你再去执行自己的静态方法。
至此一个类的加载完成了,同时再加载的过程中会生成一个class类对象,类的所有信息被加载到方法区,我们开发时通过类对象获取类信息(反射)。
BB这么多我还是想浅谈下tomcat打破双亲委派机制,当然也是为了解释下上面提到的双亲委派制机制:
这里怕自己描述的不清楚就直接copy一个标准的说法(字太多不想写)
类加载其实就有一个双亲委派机制,加载某个类时会先委托父加载器寻找目标类,找不到再委托上层父加载器加载,如果所有父加载器在自己的加载类路径下都找不到目标类,则在自己的类加载路径中查找并载入目标类。比如我们的Math类,最先会找应用程序类加载器加载,应用程序类加载器会先委托扩展类加载器加载,扩展类加载器再委托引导类加载器,顶层引导类加载器在自己的类加载路径里找了半天没找到Math类,则向下退回加载Math类的请求,扩展类加载器收到回复就自己加载,在自己的类加载路径里找了半天也没找到Math类,又向下退回Math类的加载请求给应用程序类加载器,应用程序类加载器于是在自己的类加载路径里找Math类,结果找到了就自己加载了。。双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载
为什么要这样设计,有没有太聪明想到?
1.沙箱安全机制:一些基础的包,或者直接说JRE里面lib目录下的包,或者直接看java.lang.String.class类,这样便可以防止核心API库被随意篡改.你自己偷偷写个同名的string类就想替换我API?(小朋友你涉嫌侵犯我的肖像权,准备接收传票吧)
2.防止类名重复加载
好了好了快来说下tomcat打破双亲委派,我特么都等不及了
首先说下tomcat,他是个web容器,可以部署多个应用程序,没有意见吧,那么问题来了
1.我每个应用程序可能都会使用一个第三方类库,比如JDBC,但是我使用不同的版本,如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,默认的类加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份。所以要相互隔离,每个应用程序类库互相独立,相互隔离。(打破双清委派机制,只需要实现loadclass方法,指定你要再那个目录下用哪个类加载器去加载。最终会产生多个相同的类对象,但是他们并不是同一个,因为他们的类加载器不是同一个。就问你牛逼不牛逼)
2.我每个应用程序可能都会使用一个第三方类库,比如JDBC我使用的都是一个版本,我不可能为次加载好几次类库放入虚拟机(你家内存不要钱吗,这么奢侈,人傻钱多?)
3.jsp热部署都知道,最终都会被编一个class,但是我修改jsp不会重启就能生效。因为我没个jsp都对应一个自定义类加载器,并对其监听,当发现jsp被修改我就删除对应的类加载器,重新创建类加载器,重新加载jsp文件。(就是这么豪横)
对象创建过程:
1.看类时否加载完成,没有加载先加载类
2.分配内存空间
3.初始化:给全局变量给上默认值
4.设置对象头:里面油很多东西,(锁状态,分代年龄等,)
5.执行init方法,给变量初始化数据。
补充一点:类信息再方法区,方法去占满发生full gc会回收方法区,请问满足什么条件类才会被回收
1.类的所有实例没有被GC ROOT引用,所有的堆中的对象已被回收
2.class对象没有被引用,法务在任何地方通过反射访问该类的方法
3.该类的classload被回收
从上面的第三点可以看出,除了自定义的类加载器会被回收,其他类加载器基本不可能被回收,所以,一个类想被回收基本不可能,方法区即使发生full gc 也不会回收什么类容,最终结果只会时增加xx:maxmeatspacesize大小。