如何排查Java内存泄漏?
没有经验的程序员经常认为Java的自动垃圾回收完全使他们免于担心内存管理。这是一个常见的误解:虽然垃圾收集器做得很好,但即使是最好的程序员也完全有可能成为严重破坏内存泄漏的牺牲品。让我解释一下。
当不必要地维护不再需要的对象引用时,会发生内存泄漏。这些泄漏很糟糕。首先,当程序消耗越来越多的资源时,它们会对计算机施加不必要的压力。更糟糕的是,检测这些泄漏可能很困难:静态分析通常很难精确识别这些冗余引用,现有的泄漏检测工具会跟踪和报告有关单个对象的细粒度信息,产生难以解释且缺乏精确度的结果。
换句话说,泄漏要么太难以识别,要么使用太过具体而无用术语来识别。
实际上有四类内存问题具有相似和重叠的特征,但原因和解决方案各不相同:
- Performance(性能):通常与过多的对象创建和删除,垃圾收集的长时间延迟,过多的操作系统页面交换等相关联。
- Resource constraints(资源约束):当可用内存很少或内存过于分散而无法分配大对象时 - 这可能是本机的,或者更常见的是与Java堆相关。
- Java heap leaks(java堆泄漏):经典的内存泄漏,Java对象在不释放的情况下不断创建。这通常是由潜在对象引用引起的。
- Native memory leaks(本机内存泄漏):与Java堆之外的任何不断增长的内存利用率相关联,例如由JNI代码,驱动程序甚至JVM分配。
在这个内存管理教程中,我将专注于Java堆漏洞,并概述一种基于Java VisualVM报告检测此类泄漏的方法,并利用可视化界面在运行时分析基于Java技术的应用程序。
但在您可以预防和发现内存泄漏之前,您应该了解它们的发生方式和原因。(注意:如果你能很好地处理错综复杂的内存泄漏,你可以跳过。)
1. 内存泄漏:基础
对于初学者来说,将内存泄漏视为一种疾病,将Java的OutOfMemoryError(简称OOM)视为一种症状。但与任何疾病一样,并非所有OOM都意味着内存泄漏:由于生成大量局部变量或其他此类事件,OOM可能会发生。另一方面,并非所有内存泄漏都必然表现为OOM,特别是在桌面应用程序或客户端应用程序(没有重新启动时运行很长时间)的情况下。
将内存泄漏视为疾病,将OutOfMemoryError视为症状。但并非所有OutOfMemoryErrors都意味着内存泄漏,并非所有内存泄漏都表现为OutOfMemoryErrors。
为什么这些泄漏如此糟糕?除此之外,程序执行期间泄漏的内存块通常会降低系统性能,因为分配但未使用的内存块必须在系统耗尽空闲物理内存时进行换出。最终,程序甚至可能耗尽其可用的虚拟地址空间,从而导致OOM。
2. 解密OutOfMemoryError
如上所述,OOM是内存泄漏的常见指示。实质上,当没有足够的空间来分配新对象时,会抛出错误。当垃圾收集器找不到必要的空间,并且堆不能进一步扩展,会多次尝试。因此,会出现错误以及堆栈跟踪。
诊断OOM的第一步是确定错误的实际含义。这听起来很清楚,但答案并不总是那么清晰。例如:OOM是否是因为Java堆已满而出现,还是因为本机堆已满?为了帮助您回答这个问题,让我们分析一些可能的错误消息:
- java.lang.OutOfMemoryError: Java heap space
- java.lang.OutOfMemoryError: PermGen space
- java.lang.OutOfMemoryError: Requested array size exceeds VM limit
- java.lang.OutOfMemoryError: request bytes for . Out of swap space?
- java.lang.OutOfMemoryError: (Native method)
2.1.“Java heap space”
此错误消息不一定意味着内存泄漏。实际上,问题可能与配置问题一样简单。
例如,我负责分析一直产生这种类型的OutOfMemoryError的应用程序。经过一番调查后,我发现罪魁祸首是阵列实例化,因为需要太多的内存;在这种情况下,并不是应用程序的错&#x
还没有评论,来说两句吧...