写在前面

案例介绍

这里,我将在平时工作过程中总结的内存溢出的情况,以代码案例的形式直观的分享给大家,希望能够为小伙伴们带来实质性的帮助。

接下来,我们就以代码案例的形式来分析各种内存溢出的情况。

定义主类结构

首先,我们创建一个类叫做BlowUpJVM,所有的案例实验都是基于这个类进行。

public class BlowUpJVM {
}

栈深度溢出

public static void  testStackOverFlow(){
      BlowUpJVM.testStackOverFlow();
}

栈不断递归,而且没有处理,所以虚拟机栈就不断深入不断深入,栈深度就这样溢出了。

永久代内存溢出

public static void testPergemOutOfMemory1(){
   //方法一失败
    List<String> list = new ArrayList<String>();

   while(true){
      list.add(UUID.randomUUID().toString().intern());
   }
}

打算把String常量池堆满,没想到失败了,JDK1.7后常量池放到了堆里,也能进行垃圾回收了。

然后换种方式,使用cglib,用Class把老年代取堆满

public static void testPergemOutOfMemory2(){
   try {
      while (true) {
         Enhancer enhancer = new Enhancer();
         enhancer.setSuperclass(OOM.class);
         enhancer.setUseCache(false);
         enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
               return proxy.invokeSuper(obj, args);
            }
         });
         enhancer.create();
      }
   }
   catch (Exception e){
      e.printStackTrace();
   }
}

虚拟机成功内存溢出了,那JDK动态代理产生的类能不能溢出呢?

public static void testPergemOutOfMemory3(){
   while(true){
   final OOM oom = new OOM();
   Proxy.newProxyInstance(oom.getClass().getClassLoader(), oom.getClass().getInterfaces(), new InvocationHandler() {
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = method.invoke(oom, args);
            return result;
         }
      });
   }
}

事实表明,JDK动态代理差生的类不会造成内存溢出,原因是:JDK动态代理产生的类信息,不会放到永久代中,而是放在堆中。

本地方法栈溢出

public static void testNativeMethodOutOfMemory(){
   int j = 0;
   while(true){
      Printer.println(j++);
      ExecutorService executors = Executors.newFixedThreadPool(50);
      int i=0;
      while(i++<10){
         executors.submit(new Runnable() {
            public void run() {
            }
         });
      }
   }
}

这个的原理就是不断创建线程池,而每个线程池都创建10个线程,这些线程池都是在本地方法区的,久而久之,本地方法区就溢出了。

JVM栈内存溢出

public static void testStackOutOfMemory(){
    while (true) {
            Thread thread = new Thread(new Runnable() {
                   public void run() {
                          while(true){
                      }
                   }
            });
            thread.start();
     }
}

线程的创建会直接在JVM栈中创建,但是本例子中,没看到内存溢出,主机先挂了,不是JVM挂了,真的是主机挂了,无论在mac还是在windows,都挂了。

温馨提示,这个真的会死机的。

堆溢出

public static void testOutOfHeapMemory(){
   List<StringBuffer> list = new ArrayList<StringBuffer>();
   while(true){
      StringBuffer B = new StringBuffer();
      for(int i = 0 ; i < 10000 ; i++){
         B.append(i);
      }
      list.add(B);
   }
}

不断往堆中塞新增的StringBuffer对象,堆满了就直接溢出了。

重磅福利

微信搜一搜【冰河技术】微信公众号,关注这个有深度的程序员,每天阅读超硬核技术干货,公众号内回复【PDF】有我准备的一线大厂面试资料和我原创的超硬核PDF技术文档,以及我为大家精心准备的多套简历模板(不断更新中),希望大家都能找到心仪的工作,学习是一条时而郁郁寡欢,时而开怀大笑的路,加油。如果你通过努力成功进入到了心仪的公司,一定不要懈怠放松,职场成长和新技术学习一样,不进则退。如果有幸我们江湖再见!

另外,我开源的各个PDF,后续我都会持续更新和维护,感谢大家长期以来对冰河的支持!!

11-06 10:52
查看更多