- 静态集合类引起的内存泄漏
- 场景:像
HashMap
、Vector
等静态集合类,如果一直往里面添加元素,而没有相应的清理机制,由于静态变量的生命周期与应用程序一致,这些对象不会被垃圾回收,从而导致内存泄漏。例如:
public class MemoryLeakExample {
private static Vector<Object> vector = new Vector<>();
public void addElements() {
for (int i = 0; i < 100000; i++) {
Object obj = new Object();
vector.add(obj);
}
}
}
- 原因:静态集合类的引用一直存在,使得集合内的对象无法被回收,即使这些对象在程序的其他部分已不再使用。
- 监听器注册未注销引起的内存泄漏
- 场景:在Java的图形界面编程(如Swing)或一些事件驱动的框架中,当一个对象注册了监听器,但在对象不再使用时,没有注销监听器。比如:
import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ListenerMemoryLeak {
private Frame frame;
public ListenerMemoryLeak() {
frame = new Frame("Memory Leak Example");
Button button = new Button("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);
}
// 假设这里没有提供注销监听器的方法,当frame不再使用时,监听器对象也无法被回收
}
- 原因:监听器通常会持有对注册对象的引用,即使注册对象在其他地方不再被使用,但由于监听器的引用存在,垃圾回收器无法回收注册对象,导致内存泄漏。
- 数据库连接未关闭引起的内存泄漏
- 场景:在进行数据库操作时,如果获取了数据库连接(如
Connection
对象),但在使用完毕后没有调用close()
方法关闭连接。例如:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseMemoryLeak {
public void databaseOperation() {
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
// 执行数据库操作,但是没有关闭连接
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 原因:数据库连接对象通常会占用一定的系统资源,包括内存。如果不关闭连接,这些连接对象一直处于活动状态,且其占用的资源不会被释放,随着不断获取新的连接而不关闭,就会导致内存泄漏。
- 内部类持有外部类引用引起的内存泄漏
- 场景:在Java中,如果一个非静态内部类实例被长期持有,由于非静态内部类会隐式持有外部类的引用,这可能导致外部类无法被垃圾回收。例如:
public class OuterClass {
private byte[] largeArray = new byte[1024 * 1024];
public void memoryLeakMethod() {
InnerClass inner = new InnerClass();
// 假设inner对象被长时间持有,例如添加到一个静态集合中
}
private class InnerClass {
// InnerClass实例会隐式持有OuterClass的引用
}
}
- 原因:即使
OuterClass
的其他部分在程序中已不再使用,但由于InnerClass
持有其引用,垃圾回收器无法回收OuterClass
实例,导致内存泄漏。