java内存泄露和内存溢出的实际场景

Java内存泄漏与内存溢出的实际场景

一、内存泄漏(Memory Leak)实际场景

内存泄漏是指对象不再被使用,但无法被垃圾回收器回收,导致内存被无效占用。

1. 集合类泄漏

java

复制

下载

// 案例:静态集合不断添加元素且不清理
public class CollectionLeak {
    private static List<Object> list = new ArrayList<>();
    
    public void addData(Object data) {
        list.add(data); // 数据只增不减
    }
}

场景:缓存系统未设置上限或清理策略,随着时间推移耗尽内存。

2. 监听器未注销

java

复制

下载

// 案例:添加监听器后未移除
public class ListenerLeak {
    private List<EventListener> listeners = new ArrayList<>();
    
    public void addListener(EventListener listener) {
        listeners.add(listener);
    }
    
    // 缺少removeListener方法
}

场景:GUI程序中反复打开/关闭窗口,导致旧窗口监听器堆积。

3. 线程池未关闭

java

复制

下载

ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> {...}); 
// 忘记调用executor.shutdown()

场景:Web应用中每次请求都创建新线程池,线程资源无法回收。

4. 数据库连接未关闭

java

复制

下载

try {
    Connection conn = DriverManager.getConnection(url);
    // 使用后忘记conn.close()
} catch (SQLException e) {
    e.printStackTrace();
}

场景:高频数据库操作导致连接池耗尽。

二、内存溢出(OOM)实际场景

内存溢出是指JVM内存不足以分配新对象,抛出OutOfMemoryError。

1. 堆内存溢出(Java heap space)

java

复制

下载

// 案例:加载超大文件到内存
public void loadHugeFile(String path) throws IOException {
    byte[] data = Files.readAllBytes(Paths.get(path)); // 文件大小超过堆容量
}

典型报错java.lang.OutOfMemoryError: Java heap space

2. 方法区溢出(Metaspace/PermGen)

java

复制

下载

// 案例:动态生成大量类
public class ClassGenerator {
    public void generate() {
        while(true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MyClass.class);
            enhancer.create(); // 不断生成代理类
        }
    }
}

典型报错java.lang.OutOfMemoryError: Metaspace(或PermGen space)

3. 栈溢出(StackOverflowError)

java

复制

下载

// 案例:无限递归
public class StackOverflowDemo {
    public void recursive() {
        recursive(); // 无限调用
    }
}

典型报错java.lang.StackOverflowError

4. 直接内存溢出(Direct buffer memory)

java

复制

下载

// 案例:NIO操作分配过多直接内存
ByteBuffer.allocateDirect(1024 * 1024 * 500); // 分配500MB直接内存

典型报错java.lang.OutOfMemoryError: Direct buffer memory

三、诊断与排查方法

1. 内存泄漏排

# 1. 获取堆转储文件
jmap -dump:format=b,file=heap.hprof <pid>

# 2. 使用MAT分析支配树(Dominator Tree)
# 查找占用内存最大的对象链条

2. 内存溢出排查

# 1. 查看各区内存使用
jstat -gc <pid> 1000

# 2. 调整参数获取更多信息
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/path/to/dump.hprof

四、预防措施对比

问题类型预防措施
集合泄漏使用WeakHashMap、定期清理、设置大小限制
监听器泄漏实现注销机制、使用弱引用
连接泄漏使用try-with-resources、连接池
堆溢出增加-Xmx、优化数据结构、分页处理大数据
方法区溢出增加-XX:MaxMetaspaceSize、避免动态生成过多类
栈溢出优化递归为迭代、增加-Xss
直接内存溢出合理使用ByteBuffer、增加-XX:MaxDirectMemorySize

五、典型案例分析

案例1:电商系统订单缓存泄漏

现象:每天凌晨重启才能恢复正常运行
原因:使用HashMap缓存所有历史订单,未设置过期策略
解决:改用Caffeine缓存,配置最大条目和过期时间

案例2:报表导出OOM

现象:导出大数据量报表时崩溃
原因:将全部查询结果加载到ArrayList
解决:改为流式处理,分批次读写

案例3:Android图片加载泄漏

现象:App长时间使用后卡顿
原因ImageView持有Bitmap引用,Activity销毁未清理
解决:使用WeakReferenceGlide等专业图片库

六、工具推荐

  1. 内存分析:Eclipse MAT、JVisualVM

  2. 实时监控:Arthas、Prometheus + Grafana

  3. 压力测试:JMeter、Gatling

  4. 代码扫描:FindBugs、SonarQube

通过理解这些实际场景,可以在开发过程中主动避免常见的内存问题,提高系统稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值