【Java】几种典型的内存溢出案例,都在这儿了!

摘要:
今天,我们将以Java代码的形式列出几种典型的内存溢出情况。我们希望您可以避免在日常工作中编写这些低级代码。为了定义主类结构,我们首先创建一个名为BlowUpJVM的类,然后所有的案例实验都基于这个类。JVM堆栈内存溢出publicstaticvoidtestStackOutOfMemory(){while{Threadhread=newThread;thread.start();}}线程将直接在JVM堆栈中创建。然而,在本例中,没有看到内存溢出。主机首先挂起,而不是JVM。无论是在Mac还是Windows上,真正挂起的都是主机。

写在前面

作为程序员,多多少少都会遇到一些内存溢出的场景,如果你还没遇到,说明你工作的年限可能比较短,或者你根本就是个假程序员!哈哈,开个玩笑。今天,我们就以Java代码的方式来列举几个典型的内存溢出案例,希望大家在日常工作中,尽量避免写这些low水平的代码。

定义主类结构

首先,我们创建一个名称为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对象,堆满了就直接溢出了。

测试案例完整代码

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()); 
       } 
    } 
    
    //永久代溢出
    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(); 
       } 
    } 
    
    //不会引起永久代溢出
    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; 
             } 
          }); 
       } 
    } 
    
    //本地方法栈溢出
    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() { 
                } 
             }); 
          } 
       } 
    } 
    
    //JVM内存溢出
    public static void testStackOutOfMemory(){ 
        while (true) {   
                Thread thread = new Thread(new Runnable() {   
                       public void run() { 
                              while(true){ 
                          } 
                       }   
                });   
                thread.start();   
         }   
    } 
    
    //堆溢出
    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); 
       } 
    } 
} 

写在最后

如果觉得文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习高并发编程技术。

最后,附上并发编程需要掌握的核心技能知识图,祝大家在学习并发编程时,少走弯路。

【Java】几种典型的内存溢出案例,都在这儿了!第1张

免责声明:文章转载自《【Java】几种典型的内存溢出案例,都在这儿了!》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇域函数(Qt)深受QByteArray的陷害H50073:div 循环添加点击事件,swiper循环添加点击事件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

POI导出excel模板三种方式

POI简介 POI是Apache软件基金会用java编写的免费开源的跨平台的Java API,提供API给java程序对Microsoft Office格式档案读和写的功能,一般用来操作Excel文件。用javaPOI导出Excel时,需要考虑Excel版本和数据量的问题。 JavaPOI导出Excel有三种形式: (1) 第一种HSSFWorkbook...

Tomcat中JVM内存溢出及合理配置

  Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机。Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识进行详细介绍。 一、Java JVM内存介绍 JVM管理两种类型的内存,堆和非堆。按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有...

Java内存溢出详解

一、常见的Java内存溢出有以下三种: 1.java.lang.OutOfMemoryError: Java heap space----JVM Heap(堆)溢出JVM在启动的时候会自动设置JVM Heap的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)不可超过物理内存。 可以利用JVM提供的-Xmn -Xms -Xmx等选项可进...

.net sqlite 内存溢出 问题的分析与解决。

一个小的工具网站,用了sqlite数据库,在并发小的情况一切正常,但是并发量上来之后,就报"out of memory"错误了。 分析了代码,就是很简单的根据一个条件取一段数据,并且 datareader也是释放了的。 那问题出在那里了呢?经分析,connstring每次都是实例化了一个打开,但是未关闭,也许是这个问题引起的,所以想到联接池没有启用。 在联...

内存溢出的定位与分析

概述  内存溢出在实际的生产环境中经常会遇到,比如:不断的将数据写入到一个集合中,出现了死循环,读取超大的文件等等,都可能会造成内存溢出;   如果出现了内存溢出,首先我们需要定位到发生内存溢出的环节,并且进行分析,是正还是非正常情况,如果是正常的需求,就应该考虑加大内存的设置,如果是非正常需求,那么就要对代码进行修改,修改这个bug;   首先,我们要先...

Java OOM 常见情况

Java OOM 常见情况 原文:https://blog.csdn.net/qq_42447950/article/details/81435080  1)什么是OOM?  OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError。看下关于的官方说明: Thrown when t...