我刚刚接受了一次采访,被要求用Java创建内存泄漏。
不用说,我觉得自己很傻,不知道如何开始创作。
什么样的例子?
我刚刚接受了一次采访,被要求用Java创建内存泄漏。
不用说,我觉得自己很傻,不知道如何开始创作。
什么样的例子?
当前回答
我想就如何使用JVM中可用的工具监视应用程序的内存泄漏提供建议。它没有显示如何生成内存泄漏,但解释了如何使用最少的可用工具检测内存泄漏。
您需要首先监视Java内存消耗。
最简单的方法是使用JVM附带的jstat实用程序:
jstat -gcutil <process_id> <timeout>
它将报告每一代(年轻、老年和老年)的内存消耗和垃圾收集时间(年轻和完整)。
一旦您发现一个完整的垃圾收集执行得太频繁并且花费了太多时间,您就可以假设应用程序正在泄漏内存。
然后需要使用jmap实用程序创建内存转储:
jmap -dump:live,format=b,file=heap.bin <process_id>
然后需要使用内存分析器(例如Eclipse memory Analyzer(MAT))分析heap.bin文件。
MAT将分析内存并向您提供有关内存泄漏的可疑信息。
其他回答
Swing使用对话框非常简单。创建一个JDialog,显示它,用户关闭它,然后泄漏!
您必须调用dispose()或配置setDefaultCloseOperation(dispose_ON_CLOSE)。
GUI代码中的一个常见示例是创建小部件/组件并向某个静态/应用程序范围的对象添加侦听器,然后在小部件被破坏时不删除侦听器。不仅会出现内存泄漏,而且性能也会受到影响,因为无论你听什么都会引发事件,所有的老听众都会被调用。
这里的大多数例子都“过于复杂”。它们是边缘案例。在这些例子中,程序员犯了一个错误(比如不要重新定义equals/hashcode),或者被JVM/JAVA的一个极端情况(用静态加载类…)所咬。我认为这不是面试官想要的例子,甚至不是最常见的例子。
但内存泄漏的情况确实更简单。垃圾收集器只释放不再引用的内容。我们作为Java开发人员并不关心内存。我们在需要时分配它,并让它自动释放。好的
但任何长寿命的应用程序都倾向于共享状态。它可以是任何东西,静态的,单态的。。。通常,非平凡的应用程序倾向于生成复杂的对象图。只是忘记将引用设置为null,或者更经常地忘记从集合中删除一个对象,就足以造成内存泄漏。
当然,如果处理不当,所有类型的侦听器(如UI侦听器)、缓存或任何长期共享状态都会产生内存泄漏。应该理解的是,这不是Java角落的情况,也不是垃圾收集器的问题。这是一个设计问题。我们设计为向长寿命对象添加侦听器,但在不再需要时不删除侦听器。我们缓存对象,但我们没有从缓存中删除它们的策略。
我们可能有一个复杂的图来存储计算所需的先前状态。但前一状态本身与前一状态相关联,依此类推。
就像我们必须关闭SQL连接或文件一样。我们需要设置对null的正确引用,并从集合中删除元素。我们应该有适当的缓存策略(最大内存大小、元素数量或计时器)。所有允许通知侦听器的对象必须同时提供addListener和removeListener方法。当这些通知器不再使用时,它们必须清除侦听器列表。
内存泄漏确实是可能的,而且完全可以预测。无需特殊的语言功能或角盒。内存泄漏要么是某些东西可能丢失的指示,甚至是设计问题。
对前面的答案有一点改进(为了更快地生成内存泄漏),就是使用从大型XML文件加载的DOM文档实例。
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class Main {
public static void main(String args[]) {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
((Unsafe) f.get(null)).allocateMemory(2000000000);
} catch (Exception e) {
e.printStackTrace();
}
}
}