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中有哪些常见的内存泄漏场景?的详细内容,更多请关注叮当号网其它相关文章!
文章来自互联网,只做分享使用。发布者:牧草,转转请注明出处:https://www.dingdanghao.com/article/346235.html