当前位置: 首页 > 科技观察

来人,为我炸掉那个Java虚拟机

时间:2023-03-18 13:48:58 科技观察

弹指间的电光,是我今生永恒的信念,唯有我的超强电磁炮,长盛不衰。瞬间爆炸,完成单杀。深入长文,非常非常长,执行这些程序可能会导致机器完全死机,请按照说明安全驾驶。JVM分为两部分,公共区域和堆栈私有区域。公共区域有个堆,用来放东西的。还有一个方法区,用来存放一些类信息,方法信息或者一些运行时常量信息。栈私有区分为PC寄存器(下一条操作指令的地址)、栈(临时指针和值)和局部方法区(将用于native方法调用)。今天教大家花式杀掉Java虚拟机。顺便说一句,你可以大致知道什么是GC。我们先了解一下JVM内存的结构。真正的GC信息是这样的。PSYoungGentotal3072K,used128Kedenspace2560K,5%usedsurvivorspacefromspace512K,0%usedtospace512K,0%usedParOldGentotal6656K,used408Kobjectspace6656K,6%usedPSPermGentotal4096K,used3039Kobjectspace4***%usedDestroy的第一个时期,在它的Eden区域诞生后~扫描它。如果该对象仍然可用,它将被扔到Survivor区域。如果过段时间还能用,就继续扔到OldGen区。在PerGem区,这里只放了一些类和方法。1.7之前,字符串常量池也放在这里,只有在FullGC时才会回收。有朋友会问,为什么Survivor会有from和to两个区域?这是GC策略之一。GC每次扫描Survivor区,都会直接从from到from到to复制有用的数据,这两个区相互备份,减少了内存碎片的信息收集,这样from-to-from-to来回几次次,然后将它们扔进老年代。好了,开始花式JVM吧,先把我们今天的JVM配置具体化一下,大家自己搭配吧,嗯。-Xmx10m-XX:MaxPermSize=5m-XX:MaxDirectMemorySize=5m-XX:+PrintGCDetails首先,我们的主类看起来是这样的。既然说publicclassBlowUpJVM{}花里胡哨,今天的流程就是这样。-[√]栈深度溢出-[]第一代内存溢出-[]Native方法栈溢出-[]JVM栈内存溢出-[]堆溢出publicstaticvoidtestStackOverFlow(){BlowUpJVM.testStackOverFlow();}栈继续递归,并且没有任何处理,所以虚拟机栈不断的越缩越深,栈深度简直爆炸。-[]栈深度溢出-[√]第一代内存溢出-[]Native方法栈溢出-[]JVM栈内存溢出-[]堆溢出publicstaticvoidtestPergemOutOfMemory1(){//方法1失败Listlist=newArrayList();while(true){list.add(UUID.randomUUID().toString().intern());}}本打算填满String常量池,没想到失败了,JDK1.7之后的常量pool放在堆中,也可以进行垃圾回收。马上第二次尝试,用cglib,用Class填老年代,嗯,说走就走。publicstaticvoidtestPergemOutOfMemory2(){try{while(true){Enhancerenhancer=newEnhancer();enhancer.setSuperclass(OOM.class);enhancer.setUseCache(false);enhancer.setCallback(newMethodInterceptor(){@OverridepublicObjectintercept(Objectobj,Methodmethod,Object[]args,MethodProxyproxy)throwsThrowable{returnproxy.invokeSuper(obj,args);}});enhancer.create();}}catch(Exceptione){e.printStackTrace();}}虚拟机成功gged,然后JDK动态代理生成的类会爆炸吗?publicstaticvoidtestPergemOutOfMemory3(){while(true){finalOOMoom=newOOM();Proxy.newProxyInstance(oom.getClass().getClassLoader(),oom.getClass().getInterfaces(),newInvocationHandler(){publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{Objectresult=method.invoke(oom,args);returnresult;}});}}答案是否定的!它将被回收。JDK动态代理生成的类信息不会放在第一代,而是放在堆中。-[]堆栈深度溢出-[]第一代内存溢出-[√]本机方法堆栈溢出-[]JVM堆栈内存溢出-[]堆溢出publicstaticvoidtestNativeMethodOutOfMemory(){intj=0;while(true){Printer.println(j++);ExecutorServiceexecutors=Executors.newFixedThreadPool(50);inti=0;while(i++<10){executors.submit(newRunnable(){publicvoidrun(){}});}}}这样做的原理是不断创建线程池,每个线程池创建10个线程,这些线程池都在本地方法区,随着时间的推移,本地方法区爆炸。-[]堆栈深度溢出-[]第一代内存溢出-[]本机方法堆栈溢出-[√]JVM堆栈内存溢出-[]堆溢出publicstaticvoidtestStackOutOfMemory(){while(true){Threadthread=newThread(newRunnable(){publicvoidrun(){while(true){}}});thread.start();}}线程的创建会直接在JVM栈中创建,但是在这个例子中,没有看到爆炸,而且主持人先挂断。不是JVM挂了,真的是宿主机挂了,不管是mac还是windows,都是挂了。温馨提示,这样真的会崩溃。.-[]堆栈深度溢出-[]第一代内存溢出-[]本机方法堆栈溢出-[]JVM堆栈内存溢出-[√]堆溢出publicstaticvoidtestOutOfHeapMemory(){Listlist=newArrayList();while(true){StringBufferB=newStringBuffer();for(inti=0;i<10000;i++){B.append(i);}list.add(B);}}好吧,最后最简单的在这个链接里,不断的往堆里塞新的StringBuffer对象,堆满了就直接爆掉。好的。小伙伴们,拿回去玩玩,就酱。【本文为专栏作家“大脚”原创稿件,转载请通过作者微信公众号“一个叫大脚的程序员”获得授权】点此查看本作者更多好文