MST

星途 面试题库

面试题:Java中常见的内存泄漏案例及解决方案

请列举至少两个Java中常见的内存泄漏案例,并针对每个案例阐述对应的解决方案。
41.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

案例一:静态集合类导致的内存泄漏

  1. 案例描述:当静态集合类(如static Liststatic Map)中存放对象引用时,如果这些对象在外部不再被需要,但由于静态集合持有其引用,垃圾回收器无法回收这些对象,从而造成内存泄漏。例如:
public class MemoryLeakExample {
    private static List<Object> list = new ArrayList<>();

    public void addObjectToStaticList(Object obj) {
        list.add(obj);
    }
}

在上述代码中,如果MemoryLeakExample类的addObjectToStaticList方法被多次调用,添加到list中的对象即使在外部不再使用,也不会被垃圾回收,因为list是静态的,一直持有这些对象的引用。 2. 解决方案:及时清理静态集合中的不再需要的对象。可以提供一个清理方法,例如:

public class MemoryLeakExample {
    private static List<Object> list = new ArrayList<>();

    public void addObjectToStaticList(Object obj) {
        list.add(obj);
    }

    public void clearStaticList() {
        list.clear();
    }
}

在合适的时机调用clearStaticList方法,将静态集合中的对象引用清除,让垃圾回收器可以回收这些对象。

案例二:监听器未注销导致的内存泄漏

  1. 案例描述:在Java中,经常会使用监听器模式。如果注册了监听器但没有及时注销,当被监听的对象生命周期结束时,由于监听器仍然持有对该对象的引用,导致该对象无法被垃圾回收,进而产生内存泄漏。例如:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;

public class ListenerMemoryLeak {
    private JFrame frame;
    private JButton button;

    public ListenerMemoryLeak() {
        frame = new JFrame("Listener Memory Leak");
        button = new JButton("Click me");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button clicked");
            }
        });
        frame.add(button);
        frame.pack();
        frame.setVisible(true);
    }
}

在这个简单的Swing示例中,如果ListenerMemoryLeak对象不再被需要,但没有注销按钮的监听器,JButton会一直持有监听器的引用,监听器又间接持有ListenerMemoryLeak对象的引用,使得ListenerMemoryLeak对象无法被垃圾回收。 2. 解决方案:在合适的时机注销监听器。比如,在ListenerMemoryLeak类中添加一个方法来注销监听器:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;

public class ListenerMemoryLeak {
    private JFrame frame;
    private JButton button;
    private ActionListener listener;

    public ListenerMemoryLeak() {
        frame = new JFrame("Listener Memory Leak");
        button = new JButton("Click me");
        listener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button clicked");
            }
        };
        button.addActionListener(listener);
        frame.add(button);
        frame.pack();
        frame.setVisible(true);
    }

    public void unregisterListener() {
        button.removeActionListener(listener);
    }
}

ListenerMemoryLeak对象不再需要时,调用unregisterListener方法,解除监听器与按钮之间的关联,从而避免内存泄漏。