如何识别Java中的内存泄漏

【编者按】作者Martin Gutenbrunner供职于Ruxit,拥有十年的Java Web应用程序架构和管理经验。近日,他在Dzone上撰文分享了Java内存泄漏识别相关经验,由OneAPM工程师翻译。

以下为译文

Java开发人员都知道,Java利用垃圾回收机制来自动保持应用程序内存的干净和健康。然而可能有人不知道的是,即使使用了垃圾回收机制,Java中仍然可能存在内存泄漏风险。如果你碰到下面的错误代码:

java.lang.OutOfMemoryError: Java heap space

如果你确认是内存分配不足,那么可以通过以下代码为应用程序增加可用内存:

java -Xms<initial heap size> -Xmx<maximum heap size>

不过对于内存泄漏来说这么做是治标不治本,只能起到缓解作用。

内存泄漏的识别

在将程序部署到生产环境之前检查一下是否存在内存泄漏的问题是很有必要的。这里可以通过垃圾收集器的指标来进行初步的判断。

如GC后内存使用仍然持续上升,那么就可能有内存泄漏的问题,比如上面的这幅图,代码可以查看GitHub(
https://gist.github.com/dpryden/b2bb29ee2d146901b4ae)。不过在现实中内存像图上一样线性增加的可能性是很小的,见图Old Gen,而GC suspension times或者Eden Space和Survivor空间使用并不足以识别出内存泄漏。

缩小问题的范围

要找出内存泄漏的原因当下已经有许多工具可用,比如JVisualVM或者jStat。这些工具是JDK自带的,所以大家随时都能用。除了要识别一些常用的内部Java类,一些用户自定义累同样需要识别。

性能优化

在日常的开发过程中,只要GC没有影响到性能,开发者就不会去关注内存设置于配置。从而埋下了潜在的隐患:因为内存问题并不只有溢出和泄露,GC时间过长同样会造成这个问题。比如下图中GC占用了16%的CPU。

Heap设置

Heap太小会导致频繁的GC,从而情景不难想象:增加GC会消耗更多的CPU,同时在GC时JVM会被冻结,最后导致一个很差的性能。总的来说,Heap太小的话,虽然GC时间变短,但是会变得更加频繁。

Heap太大会导致GC时间边长。GC不会经常发生,但是一旦被触发,那么VM会被冻结很久。

因此,如果这种情况下发生内存泄露,在最终JVM因为内存溢出崩溃之前,GC会非常频繁或者时间特别长。

GC版本

从Java 6开始,GC就改变了很多。Java 7引入了G1GC作为CMS GC的替代选择,而在Java 9中G1GC已成为默认选择。Java 8中移除了PermGen Space,之前存储在PermGen Space中的数据则改为存储在本地内存或者栈中。

相关文章

我的Java!越过山丘

当年我是VS程序员,2000年被微软无情抛弃时,我徘徊过,到底继续跟着微软跑还是甩了它!当时兜里没钱,没法再花精力去学习除了名字很像其他都不一样的VS.net……既然甩了微软,那我为什么不直接选一个跨...

Java内存模型的历史变迁

本文通过介绍Java的新/旧内存模型,来展示Java技术的历史变迁。旧的Java内存模型Java使用的是共享内存的并发模型,在线程之间共享变量。Java语言定义了线程模型规范,通过内存模型控制线程与变...

我们为什么要在Android中使用RxJava

感觉RxJava最近风生水起,不学习一下都不好意思了,洒家也是初学RxJava,也是感觉代码好像更复杂更难懂了,看了一篇外文感同身受,简单翻译一下。本文简单介绍使用RxJava优势所在。但可能需要有一...

详解Java中的注解

在Java中,注解(Annotation)引入始于Java5,用来描述Java代码的元信息,通常情况下注解不会直接影响代码的执行,尽管有些注解可以用来做到影响代码执行。注解可以做什么Java中的注解通...

Java反射机制剖析

java反射机制:1.指的是可以于运行时加载,探知和使用编译期间完全未知的类.2.程序在运行状态中, 可以动态加载一个只有名称的类, 对于任意一个已经加载的类,都能够知道这个类的所有属性和方法; 对于...