上文向大家演示了方法区的内存溢出
1.8以前演示了永久代可能会产生一个溢出。
1.8以后演示了元空间也有可能产生的一个溢出。
那么有同学会说,你这个两种情况都是我们自己循环了好多次,产生了一大堆class 啊,加载了一些class,导致了内存溢出。
那实际开发中我不会那么傻,我没事产生那么多class 干嘛呢?
你还真别说,那实际场景里我们动态产生class 并加载这些类的场景是非常非常多的。
举几个例子,比如说大家都学过,都用过我们的spring 框架,mybatis 框架等等。
那么这些框架里面他们都用了一些字节码技术。就比如说我们的spring 和mybatis 啊,他们都会用到cglib这样一个技术。
还记得吧?
spring 用它生成一些代理类,这些代理类呢是spring 中aop的一个核心,那么mybatis里面呢也用到了cglib,可以用cglib去产生mapper 接口的那个实现类。
这些都是它们用的cglib,cglib它的底层实际是什么呢?我们来看一下。
上文演示了这个例子中,我们用到了ClassWriter,ClassWriter我们看一下它的继承关系
它继承自一个叫ClassVisitor类,当然这个包呢由于sun/oracle公司把这个ClassWriter和ClassVisitor导入到jdk以后,他就把这个包名换了,我们看不出来原始的这个包名。
实际上它是这个叫org objectweb asm 这个项目中提供的这些ClassWriter类完成动态生成这个类的二进制字节码。
那我们不妨看一下cglib又是怎么做的。
它也有asm,这里面也有我们的这个叫ClassWriter,它也是一脉相承的集成,一个叫class visitor。当然这些包名也做了一些修改,其实他们都系出同源,是同一个东西。
也就是上文给大家演示的这个ClassWriter和cglib中的ClassWriter它们的功能都是类似的,
都是在运行期间动态生成类似字节码,完成动态的类加载,
我们的代理技术广泛应用这种字节码的动态生成技术。
所以实际情况中,我们用这种spring, mybatis 的时候,经常会产生大量的
在运行期间生成的类,其实还是很容易导致永久性的内存溢出的。当然到了1.8以后,由于元空间使用的是系统内存相对充裕了很多,并且它的垃圾回收机制也是由元空间自行来管理的。就不会像永久代一样,垃圾回收效率非常的低,经常会由于回收效率低,导致我们的内存溢出。
后面呢我们讲到了垃圾回收时,还会对比永久代和元空间。
它们在这个垃圾回收上的一个区别。现在大家要了解是我们的实际场景的话,这种动态加载类动态生成类的场景是非常多的,
使用不当都会导致这种方法区的内存溢出。所以大家不要轻视它。遇到这种问题,
我们要看看是不是你的框架使用的不合理,导致产生了太多的这个新的类型。