面试题答案
一键面试案例一:静态集合类导致的内存泄漏
- 案例描述:当静态集合类(如
static List
、static 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
方法,将静态集合中的对象引用清除,让垃圾回收器可以回收这些对象。
案例二:监听器未注销导致的内存泄漏
- 案例描述:在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
方法,解除监听器与按钮之间的关联,从而避免内存泄漏。