首页 > 图灵资讯 > 技术篇>正文
Java中有哪些常见的内存泄漏场景?
2024-04-15 13:34:09
java 常见的内存泄漏场景包括:持有外部对象引用、静态引用、无效监听器、局部线程变量和循环引用。应用服务器中常见的内存泄漏场景包括:线程保存 servlet 对象引用、静态持有器保持持久连接引用,侦听器未从组件中移除。
Java 常见的内存泄漏场景
内存泄漏是软件开发中的一个严重缺陷,随着时间的推移会导致应用程序崩溃或性能下降。以下是 Java 最常见的内存泄漏场景:
1. 引用持有对外部对象的引用
当一个对象持有引用外部对象时,JVM 当外部物体不使用时,不能回收垃圾。例如:
class Outer { private Inner inner; public Outer() { inner = new Inner(); // 持有对 Inner 的引用 } } class Inner { // ... }
登录后复制
2. 静态引用
存储静态变量 JVM 在永久内存中,它们永远不会被垃圾回收。如果引用静态变量持有对象,则该对象不能被垃圾回收。例如:
public class Example { private static List<Object> objects = new ArrayList<>(); public static void main(String[] args) { objects.add(new Object()); } }
登录后复制
3. 无效监听器
当侦听器不再使用但仍附加到事件源时,内存泄漏就会发生。例如:
import javax.swing.*; public class ListenerLeak { private JButton button; public ListenerLeak() { button = new JButton(); button.addActionListener(e -> { // ... }); } // 忘记从按钮中移除监听器 }
登录后复制
4. 局部线程变量
存储在每个线程中的线程局部变量 (TLS) 在中间,只要线程处于活动状态,它们就不会被垃圾回收。如果您在已完成的线程中使用局部线程变量,可能会导致内存泄漏。例如:
public class ThreadLocalLeak { private static ThreadLocal<Object> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { Thread thread = new Thread(() -> { threadLocal.set(new Object()); // 在线程中设置值 }); thread.start(); thread.interrupt(); // 中断线程 // 未清理局部线程存储 } }
登录后复制
5. 循环引用
当两个或两个以上的对象相互引用时,就会发生循环引用。这将导致循环引用。 JVM 无法识别它们已不再使用,导致内存泄漏。例如:
public class CycleReference { private CycleReference other; public CycleReference() { other = new CycleReference(); other.other = this; // 循环引用 } }
登录后复制
实战案例
应用服务器中的内存泄漏
以下是应用服务器中典型的内存泄漏场景:
- 线程保存对 servlet 即使是引用对象 servlet 已完成。
- 静态持有器 (如数据库连接池) 即使不再需要这些连接,也要保持引用持久连接。
- 侦听器未从组件中移除,导致保留了侦听器的引用。
通过了解常见的内存泄漏场景,并采用适当的编码实践,可以减少 Java 为了保证其稳定性和性能,应用程序中内存泄漏的风险。
Java中常见的内存泄漏场景有哪些?详情请关注图灵教育其他相关文章!