news 2026/4/25 4:36:17

一文搞懂5种内存溢出案例,内含完整源码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一文搞懂5种内存溢出案例,内含完整源码

作为程序员,多多少少都会遇到一些内存溢出的场景,如果你还没遇到,说明你工作的年限可能比较短,或者你根本就是个假程序员!哈哈,开个玩笑。今天,我们就以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); } } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 4:36:14

嵌入式C语言如何“欺骗”大模型推理引擎?——揭秘结构体对齐强制转换、定点数模拟FP16、函数指针表替代虚函数的3层伪装术

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;嵌入式C语言与轻量级大模型适配的底层逻辑 嵌入式系统资源受限的本质&#xff0c;决定了其与大模型的融合必须绕过传统推理框架的重依赖路径&#xff0c;转而从内存布局、指令集兼容性与算子原子化三个…

作者头像 李华
网站建设 2026/4/25 4:36:08

用树莓派4B和Python做个遥控小车?从PWM调速到网页控制,保姆级避坑指南

树莓派4B智能小车全栈开发指南&#xff1a;从电机控制到多终端交互 第一次看到树莓派驱动的小车在桌面上灵活转向时&#xff0c;那种成就感就像小时候拼好乐高机器人一样令人兴奋。作为创客圈最经典的入门项目&#xff0c;智能小车背后藏着不少值得玩味的技术细节——PWM调速的…

作者头像 李华
网站建设 2026/4/25 4:29:15

麒麟Kylin OS 2303上,用KDE桌面共享实现远程办公(保姆级图文教程)

麒麟Kylin OS 2303上打造高效远程办公环境&#xff1a;KDE桌面共享全攻略 在国产操作系统逐渐成熟的今天&#xff0c;麒麟Kylin OS 2303以其稳定性和安全性成为越来越多政企用户的选择。而远程办公作为现代工作方式的重要组成部分&#xff0c;如何在麒麟系统上实现流畅的桌面共…

作者头像 李华