`

聊聊内存泄露

 
阅读更多

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 堆外内存泄露的BUG是如何查找的.pdf

    。。。

    今咱们来聊聊JVM 堆外内存泄露的BUG是如何查找的.docx

    。。。

    iOS面试 内存泄漏/基础知识

    2.内存泄漏可能会出现的几种原因,聊聊你的看法? 第一种可能:第三方框架不当使用; 第二种可能:block循环引用; 第三种可能:delegate循环引用; 第四种可能:NSTimer循环引用 第五种可能:非OC对象内存处理 第六...

    iOS内存泄漏监测自动化

    被指派的第一个任务是排查AppiOS版本存在的严重的内存泄漏的问题,原因是iOS10的某些系统bug(参考文章:聊聊苹果的Bug-iOS10nano_freeCrash)导致线上出现了较多的nano_free和nano_realloc的crash问题,而这些crash...

    Android性能优化之利用强大的LeakCanary检测内存泄漏及解决办法

    最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来。所以决定抽空学习总结...

    腾讯三面以及参考思路

    内存泄漏可能会出现的几种原因,聊聊你的看法? 追问一:非OC对象如何处理? 追问二:若常用框架出现内存泄漏如何处理? 3.容错处理你们一般是注意哪些? 4.项目开始容错处理没做?如何防止拦截潜在的崩溃?

    golang面试题集合.zip

    简单聊聊内存逃逸? 字符串转成byte数组,会发生内存拷贝吗? http包的内存泄漏 sync.Map 的用法 Golang 理论 Go语言的GPM调度器是什么? Goroutine调度策略 goroutine调度器概述 Redis基础 Redis 基础数据结构 ...

    Golang 面试题汇编

    简单聊聊内存逃逸? 字符串转成byte数组,会发生内存拷贝吗? http包的内存泄漏 sync.Map 的用法 Golang 理论 Go语言的GPM调度器是什么? Goroutine调度策略 goroutine调度器概述 Redis基础 Redis 基础数据结构 ...

    一份超级详细的Java面试题【大厂面试真题+Java学习指南+工作总结】

    内存泄漏问题的分析和解决方案 程序员必备基础:加签验签 记一次接口性能优化实践总结:优化接口性能的八个建议 程序员必备基础:如何安全传输存储用户密码? 一次代码优化实践,用了模板方法+策略+工厂方法模式 ...

    Article::light_bulb:个人博客

    内存管理与内存泄漏思考题 深入js之内存管理与内存泄漏 深入js之深究ES6规范前后的执行上下文相关 2018 用 Vue 开发仿旅游站 webapp 项目总结 (下) 用 Vue 开发仿旅游站 webapp 项目总结 (上) 标注图 + 部分举例...

    interview-go:golang面试题集合

    简单聊聊内存逃逸? 字符串转成byte数组,会发生内存拷贝吗? http包的内存泄漏 Golang 理论 Go语言的GPM调度器是什么? Goroutine调度策略 goroutine调度器概述 Redis基础 Redis 基础数据结构 Redis中的底层数据...

    I need AV,Tomcat(翻译一下:我需要安慰,Tomcat)

    细聊才知道,他所负责的一个项目,生产环境上一个Tomcat开启了热加载模式,导致引起内存泄漏,造成生产事故,排查很长时间,具体细节就不讲了。另外说说这个Tomcat,其实是我同事养的一只小猫咪,由于他是做软件这一...

    sdkdemoapp3.0_android

    (2)有效避免生命周期组件内存泄漏。 (3)提高模块可测试性。 (4)提高应用稳定性,有效降低以下异常发生概率。 二、新项目对工具的要求: (1)Android Studio 3.2或更高版本。 (2)SDK targetVersion至少为26...

    AsyncAwaitBestPractices:System.Threading.Tasks.Task和System.Threading.Tasks.ValueTask的扩展

    : SafeFireAndForget 一种安全触发并忘记Task或ValueTask的扩展方法确保Task将重新抛出Exception如果一个Exception被抓IAsyncStateMachine.MoveNext() WeakEventManager 避免在未取消订阅事件时发生内存泄漏由...

Global site tag (gtag.js) - Google Analytics