10分钟搞懂各种内存溢出案例!!!

存储
今天,我们就以Java代码的方式来列举几个典型的内存溢出案例,希望大家在日常工作中,尽量避免写这些low水平的代码。

[[402096]]

大家好,我是冰河~~

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

我们先来看看今天要介绍哪些内存溢出案例,冰河这里总结了一张图,如下所示。

说干就干,咱们开始吧!!

定义主类结构

首先,我们创建一个名称为BlowUpJVM的类,之后所有的案例实验都是基于这个类进行。如下所示。

  1. public class BlowUpJVM {   
  2. }  

栈深度溢出

  1. public static void testStackOverFlow(){ 
  2.  
  3. BlowUpJVM.testStackOverFlow(); 
  4.  

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

永久代内存溢出

  1. public static void testPergemOutOfMemory1(){  
  2.    //方法一失败  
  3.    List<String> list = new ArrayList<String>();  
  4.    while(true){  
  5.       list.add(UUID.randomUUID().toString().intern());  
  6.    }  
  7. }  

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

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

  1. public static void testPergemOutOfMemory2(){  
  2.    try {  
  3.       while (true) {  
  4.          Enhancer enhancer = new Enhancer();  
  5.          enhancer.setSuperclass(OOM.class);  
  6.          enhancer.setUseCache(false);  
  7.          enhancer.setCallback(new MethodInterceptor() {  
  8.             @Override  
  9.             public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {  
  10.                return proxy.invokeSuper(obj, args);  
  11.             }  
  12.          });  
  13.          enhancer.create();  
  14.       }  
  15.    }  
  16.    catch (Exception e){  
  17.       e.printStackTrace();  
  18.    }  
  19. }  

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

  1. public static void testPergemOutOfMemory3(){  
  2.    while(true){  
  3.    final OOM oom = new OOM();  
  4.    Proxy.newProxyInstance(oom.getClass().getClassLoader(), oom.getClass().getInterfaces(), new InvocationHandler() {  
  5.          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  6.             Object result = method.invoke(oom, args);  
  7.             return result;  
  8.          }  
  9.       });  
  10.    }  
  11. }  

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

本地方法栈溢出

  1. public static void testNativeMethodOutOfMemory(){  
  2.    int j = 0;  
  3.    while(true){  
  4.       Printer.println(j++);  
  5.       ExecutorService executors = Executors.newFixedThreadPool(50);  
  6.       int i=0;  
  7.       while(i++<10){  
  8.          executors.submit(new Runnable() {  
  9.             public void run() {  
  10.             }  
  11.          });  
  12.       }  
  13.    }  
  14. }  

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

JVM栈内存溢出

  1. public static void testStackOutOfMemory(){  
  2.     while (true) {    
  3.             Thread thread = new Thread(new Runnable() {    
  4.                    public void run() {  
  5.                           while(true){  
  6.                       }  
  7.                    }    
  8.             });    
  9.             thread.start();    
  10.      }    
  11. }  

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

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

堆溢出

  1. public static void testOutOfHeapMemory(){  
  2.    List<StringBuffer> list = new ArrayList<StringBuffer>();  
  3.    while(true){  
  4.       StringBuffer B = new StringBuffer();  
  5.       for(int i = 0 ; i < 10000 ; i++){  
  6.          B.append(i);  
  7.       }  
  8.       list.add(B);  
  9.    }  
  10. }  

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

测试案例完整代码

  1. public class BlowUpJVM { 
  2.     //栈深度溢出 
  3.     public static void  testStackOverFlow(){  
  4.        BlowUpJVM.testStackOverFlow();  
  5.  }  
  6.      
  7.     //不能引起永久代溢出 
  8.     public static void testPergemOutOfMemory1(){  
  9.        //方法一失败  
  10.         List<String> list = new ArrayList<String>();  
  11.        while(true){  
  12.           list.add(UUID.randomUUID().toString().intern());  
  13.        }  
  14.     }  
  15.      
  16.     //永久代溢出 
  17.     public static void testPergemOutOfMemory2(){  
  18.        try {  
  19.           while (true) {  
  20.              Enhancer enhancer = new Enhancer();  
  21.              enhancer.setSuperclass(OOM.class);  
  22.              enhancer.setUseCache(false);  
  23.              enhancer.setCallback(new MethodInterceptor() {  
  24.                 @Override  
  25.                 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {  
  26.                    return proxy.invokeSuper(obj, args);  
  27.                 }  
  28.              });  
  29.              enhancer.create();  
  30.           }  
  31.        }  
  32.        catch (Exception e){  
  33.           e.printStackTrace();  
  34.        }  
  35.     }  
  36.      
  37.     //不会引起永久代溢出 
  38.     public static void testPergemOutOfMemory3(){  
  39.        while(true){  
  40.        final OOM oom = new OOM();  
  41.        Proxy.newProxyInstance(oom.getClass().getClassLoader(), oom.getClass().getInterfaces(), new InvocationHandler() {  
  42.              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  43.                 Object result = method.invoke(oom, args);  
  44.                 return result;  
  45.              }  
  46.           });  
  47.        }  
  48.     }  
  49.      
  50.     //本地方法栈溢出 
  51.     public static void testNativeMethodOutOfMemory(){  
  52.        int j = 0;  
  53.        while(true){  
  54.           Printer.println(j++);  
  55.           ExecutorService executors = Executors.newFixedThreadPool(50);  
  56.           int i=0;  
  57.           while(i++<10){  
  58.              executors.submit(new Runnable() {  
  59.                 public void run() {  
  60.                 }  
  61.              });  
  62.           }  
  63.        }  
  64.     }  
  65.      
  66.     //JVM内存溢出 
  67.     public static void testStackOutOfMemory(){  
  68.         while (true) {    
  69.                 Thread thread = new Thread(new Runnable() {    
  70.                        public void run() {  
  71.                               while(true){  
  72.                           }  
  73.                        }    
  74.                 });    
  75.                 thread.start();    
  76.          }    
  77.     }  
  78.      
  79.     //堆溢出 
  80.     public static void testOutOfHeapMemory(){  
  81.        List<StringBuffer> list = new ArrayList<StringBuffer>();  
  82.        while(true){  
  83.           StringBuffer B = new StringBuffer();  
  84.           for(int i = 0 ; i < 10000 ; i++){  
  85.              B.append(i);  
  86.           }  
  87.           list.add(B);  
  88.        }  
  89.     }  
  90. }  

写在最后

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

本文转载自微信公众号「冰河技术」,可以通过以下二维码关注。转载本文请联系冰河技术公众号。

 

责任编辑:武晓燕 来源: 冰河技术
相关推荐

2017-03-30 19:28:26

HBase分布式数据

2021-06-18 07:34:12

Kafka中间件微服务

2019-08-09 10:33:36

开发技能代码

2021-07-15 06:43:11

Bash调试脚本

2023-12-06 08:48:36

Kubernetes组件

2013-09-13 14:08:01

2014-08-08 09:30:04

android scrollview

2020-10-13 18:22:58

DevOps工具开发

2024-01-16 07:46:14

FutureTask接口用法

2023-09-18 15:49:40

Ingress云原生Kubernetes

2022-05-23 09:10:00

分布式工具算法

2019-06-14 09:34:59

Linux 系统 数据

2021-04-23 09:50:41

topLinux命令

2017-01-18 15:38:20

语言

2021-05-17 20:13:50

数仓操作型数据库

2024-01-12 07:38:38

AQS原理JUC

2020-03-03 15:40:51

开发技能代码

2019-09-16 09:14:51

2023-12-04 18:13:03

GPU编程

2021-08-01 21:38:07

网页点灯网关
点赞
收藏

51CTO技术栈公众号