永久代或者元空间溢出模拟
首先里面存了什么?
类型信息,常量,静态变量,即时编译后的代码缓存。
常量嘛,String.intern(),JDK6及之前可以,但是JDK7起就将字符串常量池,静态变量移入堆中了。
类型信息,即时代码缓存,基本一对一的东西。
在JDK7后,用户能动的也就它了。那只要能无限增加类型信息就行了呗。
问题简化为在运行期不断创建新的类型信息,不断加载。
cglib就可以在运行期动态创建类。
cglib默认开启了UserCache生成的代理类都会复用原先产生在缓存中的类,所以至始至终都只有一个代理类,所以不会产生内存溢出。手动关闭它,代码如下
笔者是JDK8配置-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m。 JDK6的配置自行查询
public class RealService { public void realMethod() { System.out.println("realMethod execute"); } public static void main(String[] args) { //设置代理类生成目录 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/wangzhigang/temp"); Enhancer enhancer = new Enhancer(); enhancer.setUseCache(false); //设置超类,因为cglib基于父类 生成代理子类 enhancer.setSuperclass(RealService.class); //设置回调,也就是我们的拦截处理 enhancer.setCallback(new MyServiceInterceptor()); //创建代理类 RealService realService = (RealService) enhancer.create(); for (int i = 0; i < 1000; i++) { System.out.println(i); realService = (RealService) enhancer.create(); } //代用代理类的方法 realService.realMethod(); } }
public class MyServiceInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("before exexute"); Object result=methodProxy.invokeSuper(obj, objects); System.out.println("after exexute"); return result; } }
523 524 525 526 Exception in thread "main" org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345) at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:492) at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:114) at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291) at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:480) at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:305) at com.hhdd.controller.book2.RealService.main(RealService.java:63) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:459) at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336) ... 6 more Caused by: java.lang.OutOfMemoryError: Metaspace at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ... 11 more