开发易忽视的问题:内存溢出/泄漏案例

内存溢出和内存泄漏区别

对比项 内存溢出(OOM) 内存泄漏(Memory Leak)
定义 程序请求的内存超出了 JVM 可用内存 不再使用的对象仍然被引用,导致 GC 无法回收
本质 申请的内存超限,无法再分配 对象的生命周期比预期更长,导致无用对象占用内存
影响 直接导致程序崩溃 程序运行变慢,可能最终导致 OOM
原因 过多对象创建、JVM 配置不足、无限递归等 没有释放资源(如静态集合、线程、Socket、数据库连接等)
修复方法 优化代码、增加 JVM 堆大小、减少无用对象 及时释放资源、使用弱引用(WeakReference)、优化对象管理

溢出案例

现象 :不断向 堆(Heap) 中分配内存,导致 java.lang.OutOfMemoryError: Java heap space。

案例

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class HeapOOM {
    static class OOMObject {}

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while (true) {
            list.add(new OOMObject()); // 不断向 list 添加对象,导致堆溢出
        }
    }
}

原因

  • 不断创建新对象,导致 堆内存被占满,GC 也无法回收。

解决方案

  • 代码优化,避免对象长时间引用
  • 使用 WeakReference 进行缓存管理

泄漏案例

java 复制代码
// Leak example
import java.util.HashMap;
import java.util.Map;

public class HashMapLeakDemo {
    public static class Key {
        String title;

        public Key(String title) {
            this.title = title;
        }
    }

    public static void main(String[] args) {
        Map<Key, Integer> map = new HashMap<>();
        map.put(new Key("1"), 1);
        map.put(new Key("2"), 2);
        map.put(new Key("3"), 2);

        Integer integer = map.get(new Key("2"));
        System.out.println(integer);
    }
}

📌 问题分析 :

  1. Key 类没有 重写 equals() 和 hashCode() 方法。
  2. HashMap 依赖 hashCode() 计算存储位置 ,new Key("2") 生成的是新对象,默认 hashCode() 不是同一个,导致 get(new Key("2")) 返回 null。
  3. 解决方案 :重写 equals() 和 hashCode() 方法,保证 Key 对象逻辑相等时哈希值一致。

💡 修正代码:

java 复制代码
public static class Key {
    String title;

    public Key(String title) {
        this.title = title;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Key key = (Key) obj;
        return title.equals(key.title);
    }

    @Override
    public int hashCode() {
        return title.hashCode();
    }
}

🔹 这样 map.get(new Key("2")) 就能正确返回 2 了! 🚀

即使提供了 equals 方法和 hashCode 方法,也要非常小心,尽量避免使用自定义的对象作为 Key。

相关推荐
瑞码空间20 分钟前
面向接口编程与开闭原则在模拟 JDBC 驱动中的应用
java·jdbc
zhoujungis31 分钟前
登录态 1 小时就掉?Django + Vue 双 Token 认证实战 | 尘世栈帧
后端
Félix25137 分钟前
Nacos学习笔记(SpringBoot/SpringCloud)
java·spring boot·spring
文丑颜不良啊42 分钟前
LeetCode1581~1600题目解析
java·leetcode
香蕉大香蕉(06敬畏市场)42 分钟前
MySQL 单点详解(06)
java·数据库·mysql·博客·实习
滼1 小时前
AI 数据安全面试应答框架:从大框架到小点
大数据·人工智能·安全·面试·安全架构
武子康1 小时前
同一台 ESP32,GSM 能消回声,VoIP 为什么不行?
人工智能·后端·agent
用户69371750013841 小时前
AI 能写代码,但工程架构还是应该由人来定
前端·后端
lqbzlll1 小时前
Spring Boot 开启虚拟线程后接口反而变慢了?4 个排查方向和对应修法
java·spring boot·后端
七夜zippoe1 小时前
LangChain4j vs Spring AI:Java AI 框架怎么选(对比表)
java·人工智能·spring·ai·langchain4j