文档章节

聊聊内存泄露

lateron
 lateron
发布于 2013/05/29 17:46
字数 1120
阅读 2001
收藏 90

个人博客:http://shellblog.sinaapp.com/

1.什么是内存泄露

看到网上有很多人都在问内存泄露与内存溢出的区别(CSDN上),而且后面还有一大堆的跟帖在用不同形式的语言予以解答,我看了以后思绪万千啊。内存泄露是导致内存溢出的原因之一,说他们的区别纯属无稽之谈。要解释什么是内存泄露还真是个费事的活,我用一个例子来解释下:

public class Test {

	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		while (true) {
			String test = new String("111");
			list.add(test);
		}
	}
}
上面的代码会不停的往list中添加数据,当我们的堆空间不足时,就会报OOM的错误,如下:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.leak.Test.main(Test.java:11)


当堆空间不足的时候,JVM会进行垃圾回收,但是垃圾回收时却发现这些对象都是有用的,不能回收。我们可能会考虑增大堆空间大小,可是这还是于是无补,因为我们有个死循环。这种情况其实就是内存泄露的一个简单例子,简而言之,如果是内存泄露引起的OOM,那肯定是我们代码有问题,需要修正代码。

2.如何确定OOM是由于内存泄露引起的

在工作中,遇到OOM,你首先要确定他是由于什么原因引起的?是因为堆空间设置太小引起还是因为内存泄露引起。实际上,内存泄露的问题可以通过增大堆空间暂时得到解决,但是他不是长久之计。

我们可以通过对应用访问峰值时堆空间利用率的分析来确定应用是否存在内存泄露,比如我们可以用JMeter来进行压力测试,我们每次对应用加压1000,一共加压10次,第一次峰值时堆使用了100M,第二次峰值时使用了200M,第三次峰值时使用了300M....那这样我们基本可以确定应用存在内存泄露。因为正常情况下,每次峰值时的堆占用率应该是差不多的,而上面的例子每次峰值时数据出入都比较大,而且是逐步增加,这不是一个正常的现象。

观察内存的使用情况,你可以使用JConsole或者VisualVM等工具,我比较喜欢从GC的日志中得到我想要的信息,每次峰值时由于堆空间吃紧,肯定会触发一次GC,我通过这几次GC记录可以明了的看到堆内存情况。我们可以通过配置JVM参数来启用一些基本的GC日志,比如-verbose:gc、-XX:+PrintGCTimeStamps、-XX:+PrintGCDetails、-Xloggc:<file>。至于如何读GC日志,我博客里有其他文章讲解,oracle官网也有比较好的例子。

总结一下,如何确定应用存在内存泄露问题,我们需要观察峰值时的堆内存变化,比如堆的使用情况像下图一样,那肯定是存在Memory Leak了。

3.如何定位引起内存泄露的代码

首先我们可以看发生OOM时的代码,比如上面的例子,我们大概可以知道在执行哪段代码时发生了错误,然后重点看下这部分代码。当然,那部分代码不一定就是导致OOM的代码。

接下来我们需要分析堆快照,可以为JVM配置发生OOM时出生堆快照文件(+XX:+HeapDumpOnOutOfMemoryError),或者使用jmap命令产生。注意生成堆快照文件时应用会停止运行,所以千万不要在生产环境中这么搞。

拿到堆快照文件后,我们使用Mat或者VisualVM工具进行分析。借助这些工具,我们可以根据实例数、占用大小对目前堆中的所有实例进行排序,那排在前几位的就是你要重点分析的。

前面讲的方法很容易就能找出大范围的Memory Leak代码,但是对于一些小的内存溢出问题,我们可能就比较难发现了,我的经验是先定位是哪些功能点引起的内存泄露,然后重点去压这部分功能,放大他们的影响之后再去分析。

© 著作权归作者所有

下一篇: JVM的年轻代
lateron

lateron

粉丝 172
博文 57
码字总数 44492
作品 1
海淀
私信 提问
加载中

评论(12)

xiaobao36
xiaobao36
不错,标记了
lateron
lateron 博主

引用来自“karlcoder”的评论

第一个例子哪里是什么内存泄露啊!不是c/c++码农连啥是泄露都理解不了。

博客例子举的确实欠佳,在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。笔者的意思在程序中没有表达清楚,即我想出了循环,这些string就没有生存的必要了。也就是都是无用对象了。谢谢指正。参考自:http://www.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/
lateron
lateron 博主

引用来自“karlcoder”的评论

引用来自“夕水溪下”的评论

引用来自“karlcoder”的评论

第一个例子哪里是什么内存泄露啊!不是c/c++码农连啥是泄露都理解不了。

愿闻其详

内存泄露是指分配的内存还未被释放,但程序中已经没有了指向这片内存的指针/引用。处在这种状态的内存就叫垃圾内存。有垃圾回收就不会真正泄露,但溢出不可避免。泄露是逻辑错误导致,溢出是物理限制导致。泄露只是有可能导致溢出,也不是导致溢出的唯一原因。你第一个例子中已分配内存的引用都在,所以不存在泄露。

或者这样理解,在添加完string后,将string置为null。
lateron
lateron 博主

引用来自“karlcoder”的评论

引用来自“夕水溪下”的评论

引用来自“karlcoder”的评论

第一个例子哪里是什么内存泄露啊!不是c/c++码农连啥是泄露都理解不了。

愿闻其详

内存泄露是指分配的内存还未被释放,但程序中已经没有了指向这片内存的指针/引用。处在这种状态的内存就叫垃圾内存。有垃圾回收就不会真正泄露,但溢出不可避免。泄露是逻辑错误导致,溢出是物理限制导致。泄露只是有可能导致溢出,也不是导致溢出的唯一原因。你第一个例子中已分配内存的引用都在,所以不存在泄露。

一般来说内存泄漏有两种情况。一种情况如在C/C++语言中的,在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。第一种情况,在Java中已经由于垃圾回收机制的引入,得到了很好的解决。所以,Java中的内存泄漏,主要指的是第二种情况。而上面的例子中,出了循环对象已经没有存在的意义。
k
karlcoder

引用来自“夕水溪下”的评论

引用来自“karlcoder”的评论

第一个例子哪里是什么内存泄露啊!不是c/c++码农连啥是泄露都理解不了。

愿闻其详

内存泄露是指分配的内存还未被释放,但程序中已经没有了指向这片内存的指针/引用。处在这种状态的内存就叫垃圾内存。有垃圾回收就不会真正泄露,但溢出不可避免。泄露是逻辑错误导致,溢出是物理限制导致。泄露只是有可能导致溢出,也不是导致溢出的唯一原因。你第一个例子中已分配内存的引用都在,所以不存在泄露。
lateron
lateron 博主

引用来自“karlcoder”的评论

第一个例子哪里是什么内存泄露啊!不是c/c++码农连啥是泄露都理解不了。

愿闻其详
k
karlcoder
第一个例子哪里是什么内存泄露啊!不是c/c++码农连啥是泄露都理解不了。
whaon
whaon
学习下
UlricQin
UlricQin
牛逼
哎哎哎哎啊
哎哎哎哎啊
写得非常好
今咱们来聊聊JVM 堆外内存泄露的BUG是如何查找的

前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤了Bug的源头。笔者将此Bug分析的过程写...

美的让人心动
2018/04/24
69
0
纳尼,Java 存在内存泄泄泄泄泄泄漏吗?

01. 怎么回事? 纳尼,Java 不是自动管理内存吗?怎么可能会出现内存泄泄泄泄泄泄漏! Java 最牛逼的一个特性就是垃圾回收机制,不用像 C++ 需要手动管理内存,所以作为 Java 程序员很幸福,...

ityouknow
05/23
0
0
大数据时代,揭露个人数据泄漏和秘密跟踪内幕

网联网、社交网络技术的发展给人们的生活带了很多方便,例如网上聊天、网上购物、视频和社交等成了我们生活的新常态,据最新统计数据显示,我国网民总数已达7.1亿。但是,互联网在给我们生活...

hardywang
2018/07/04
0
0
内存溢出(oom)和内存泄露(leak)

在系统内存严重不足时,可能触发OOM killer。 1.OOM kiler a. 问:oomscore的默认值是多少? 答:0,oomscore=0时禁止内核杀死进程。 b. 问:oomscore如何设置? 答:两个方式,手动设置或通过...

苗永超
2016/02/20
255
0
Android 内存泄露优化处理

参考: Android应用内存泄露分析、改善经验总结 使用新版Android Studio检测内存泄露和性能 解决安卓CPU使用率过高问题 Android CPU使用过大的问题解决以及造成的原因 AndroidStudio CPU Mo...

天鬼
2017/11/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot 2 实战:使用 Spring Boot Admin 监控你的应用

1. 前言 生产上对 Web 应用 的监控是十分必要的。我们可以近乎实时来对应用的健康、性能等其他指标进行监控来及时应对一些突发情况。避免一些故障的发生。对于 Spring Boot 应用来说我们可以...

码农小胖哥
41分钟前
4
0
ZetCode 教程翻译计划正式启动 | ApacheCN

原文:ZetCode 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远。 ApacheCN 学习资源 贡献指南 本项目需要校对,欢迎大家提交 Pull Request。 ...

ApacheCN_飞龙
52分钟前
4
0
CSS定位

CSS定位 relative相对定位 absolute绝对定位 fixed和sticky及zIndex relative相对定位 position特性:css position属性用于指定一个元素在文档中的定位方式。top、right、bottom、left属性则...

studywin
今天
6
0
从零基础到拿到网易Java实习offer,我做对了哪些事

作为一个非科班小白,我在读研期间基本是自学Java,从一开始几乎零基础,只有一点点数据结构和Java方面的基础,到最终获得网易游戏的Java实习offer,我大概用了半年左右的时间。本文将会讲到...

Java技术江湖
昨天
5
0
程序性能checklist

程序性能checklist

Moks角木
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部