MST

星途 面试题库

面试题:Java中常见导致内存泄漏的场景及如何初步检测

请列举至少三种Java中常见的可能导致内存泄漏的场景,并简要说明如何通过简单的工具或代码检查初步检测是否存在内存泄漏。
18.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

常见导致内存泄漏的场景

  1. 静态集合类导致的内存泄漏:像 static HashMapstatic List 等,如果在其中不断添加对象,且这些对象不再被其他地方需要,但因为静态集合持有其引用,垃圾回收器无法回收这些对象,从而造成内存泄漏。
  2. 对象之间相互引用导致的内存泄漏:例如类A持有类B的引用,类B又持有类A的引用,且它们的生命周期很长。如果在程序中不再需要这两个对象,但因为相互引用,垃圾回收器无法回收它们,就会造成内存泄漏。
  3. 资源未关闭导致的内存泄漏:比如数据库连接(Connection)、文件流(FileInputStream 等)、网络连接(Socket)等资源,如果使用完后没有正确关闭,这些对象会一直占用内存,导致内存泄漏。
  4. 内部类持有外部类引用导致的内存泄漏:如果内部类对象的生命周期比外部类对象长,且内部类持有外部类的引用,那么即使外部类对象不再被使用,由于内部类的存在,外部类对象也无法被垃圾回收,从而导致内存泄漏,常见于Android开发中的匿名内部类。

初步检测内存泄漏的方法

  1. 使用VisualVM
    • 启动VisualVM:可以在JDK的bin目录下找到 jvisualvm.exe 并启动。
    • 连接到目标Java进程:在VisualVM界面中,找到并选中要监控的Java进程。
    • 分析堆内存:在 “监视” 选项卡中,可以看到堆内存的使用情况。切换到 “堆Dump”,点击 “生成” 可以获取堆内存快照。通过分析快照,查看对象数量和大小,如果发现某些对象数量异常多或者占用内存过大且不符合程序逻辑,可能存在内存泄漏。
  2. 使用JProfiler
    • 启动JProfiler:安装并启动JProfiler工具。
    • 连接到Java进程:按照提示连接到要检测的Java进程。
    • 监控内存使用:在JProfiler界面中,可以实时监控内存使用情况,包括对象的创建和销毁。使用 “内存视图” 等功能,分析对象的生命周期,如果发现某些对象长时间存在且没有被合理释放,可能存在内存泄漏。
  3. 代码中添加内存监控代码: 在代码中定时打印内存使用情况,例如:
public class MemoryMonitor {
    public static void main(String[] args) {
        long totalMemory = Runtime.getRuntime().totalMemory();
        long freeMemory = Runtime.getRuntime().freeMemory();
        long usedMemory = totalMemory - freeMemory;
        System.out.println("Total Memory: " + totalMemory);
        System.out.println("Free Memory: " + freeMemory);
        System.out.println("Used Memory: " + usedMemory);
    }
}

如果在程序运行过程中,发现已使用内存(usedMemory)持续增长且没有合理的下降趋势,可能存在内存泄漏。