副标题 / 摘要

Java 有 GC 也会出现内存泄漏。本文用经典栈实现解释为什么对象引用没清理会导致泄漏。

目标读者

  • 使用 Java 的开发者
  • 关注内存问题的工程师
  • 需要理解引用机制的人

背景 / 动机

GC 只能回收“不可达对象”。
如果引用没清理,哪怕对象不再需要,也不会被回收。

核心概念

  • 对象可达性:决定是否可回收
  • 引用残留:对象仍被数组引用
  • 逻辑泄漏:对象不再使用却无法回收

实践指南 / 步骤

  1. 识别不再使用的引用
  2. 在 pop 后显式置空
  3. 使用工具分析堆快照
  4. 写回归测试验证

可运行示例

import java.util.EmptyStackException;
import java.util.Arrays;

public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0) throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null; // 防止内存泄漏
        return result;
    }

    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}

解释与原理

数组中残留的引用使对象仍然“可达”。
显式置空可以让 GC 回收对象。

常见问题与注意事项

  1. GC 不会自动清理吗?
    GC 只处理不可达对象。

  2. 这种泄漏常见吗?
    在缓存、集合中非常常见。

  3. 如何排查?
    用堆快照工具(MAT、VisualVM)。

最佳实践与建议

  • 对可变集合及时清理引用
  • 对缓存设置过期机制
  • 定期做内存分析

小结 / 结论

Java 内存泄漏多来自“引用未清理”。
理解可达性是避免泄漏的关键。

参考与延伸阅读

  • Effective Java: Item 7
  • Java Memory Leak Guide

元信息

  • 阅读时长:6~8 分钟
  • 标签:内存管理、Java
  • SEO 关键词:Java 内存泄漏, 引用清理
  • 元描述:解释 Java 栈实现中的内存泄漏。

行动号召(CTA)

检查你的缓存或集合是否清理引用,避免逻辑泄漏。