类加载机制

在加载阶段,就是找到需要加载的类并把类的信息加载到jvm的方法区中。,

      1.根据类的全路径名找到相应的class文件,然后从class文件中读取文件内容;

      2. 从jar文件中读取。

图中constant pool部份,他就是常量池的一部份。它会被加载至方法区中的运行常量池中,而类中的其它部份(类的元数据)则放在另一块。

在JDK8中,运行常量池已被放入堆中,而元数据放入元空间。

元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存(内存概述与JAVA进程内存中的末使用区域)限制,但可以通过以下参数来指定元空间的大小:

-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。
除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

因为JAVA类的加载的动态性,在JDK7的时候,如果你一开始给方法区设置了很小的值,JAVA在运行时候类越加越多,则会OOM,如果一开始过大,JAVA运行时没多少的类,则会浪费空间。而现在放在元空间的话,他过大则会向本地内存继续申请,过小就会把内存还回去(末使用区域由操作系统调节,置换出内存页)。

 

类加载器—双亲委派机制

从右图中ClassLoader中loadClass源码中可以看到,从当前加载器进行逆向查找一个类是不是已被加载,如果被加载过了,则返回父级的加载器。如果找不到才调用 findClass查找。再结合左图,就是BootSrap加载了一个类,其它的加载器都不能加载。

JVM中的类加载器使用的是双亲委派机制。为何要用?

判断两个类相同的前提是这两个类都是同一个加载器进行加载的,如果使用不同的类加载器进行加载同一个类,也会有不同的结果。如果没有双亲委派机制,会出现什么样的结果呢?

比如我们在rt.jar中随便找一个类,如java.util.HashMap,那么我们同样也可以写一个一样的类,也叫java.util.HashMap存放在我们自己的路径下(ClassPath).那样这两个相同的类采用的是不同的类加载器,系统中就会出现两个不同的HashMap类,这样引用程序就会出现一片混乱。

 

常量池及元空间实验

字符串常量池是jdk6是方法区的一部分。用于存放编译期间生成的字符串常量《JVM常量池》。现在已移到堆区(图中的OOM是从堆中报出来的)
 

一直用不同的加载器加载类,他会导致我们的元空间一直变大,因为元空间默认为系统空闲内存的大小

给他加上-XX:MaxMetaspaceSize=10M参数的时候,他分分钟钟的爆了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值