`

聊聊内存泄露

 
阅读更多

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代码,但是对于一些小的内存溢出问题,我们可能就比较难发现了,我的经验是先定位是哪些功能点引起的内存泄露,然后重点去压这部分功能,放大他们的影响之后再去分析。

分享到:
评论

相关推荐

    聊聊 C 语言的内存模型与指针

    了解C语言的内存模型,有助于开发者更高效地使用内存资源,避免内存泄漏等问题,同时深入理解指针的作用也至关重要,因为指针与内存分配和管理紧密相关。 C语言的内存模型通常可以划分为几个不同的区域,包括程序...

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

    。。。

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

    。。。

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

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

    【JavaScript源代码】详细聊聊浏览器是如何看闭包的.docx

    ### 详细聊聊浏览器是如何看待闭包的 #### 前言 闭包是JavaScript中一个重要的概念,同时也是学习过程中的一个难点。对于许多开发者来说,虽然接触过不少关于闭包的文章,但真正能够深入理解并灵活运用闭包的并不多...

    理解JAVA虚拟机-内存管理、垃圾收集器.pptx

    在实际应用中,频繁的Full GC、不合理的内存设置以及内存泄露都是可能导致性能问题的因素,需要通过上述工具进行监控和分析,以便进行有效的内存管理和优化。对于内存排查,可以使用-jmap生成heap dump,然后用MAT...

    APP源码分享—微聊

    为了保证用户体验,微聊可能进行了内存优化、启动速度优化、图片加载优化等工作,如使用Glide或Picasso加载图片,避免内存泄漏。 通过深入学习微聊的源码,开发者不仅可以提升Android开发技能,还能了解即时通讯...

    Java高级知识点详解系列

    了解对象生命周期和内存泄漏的概念对于优化程序性能至关重要。 2. **泛型**:泛型是Java 5引入的一项特性,增强了代码的类型安全性和效率。泛型允许在类、接口和方法定义时指定参数类型,从而在编译阶段就能发现...

    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 基础数据结构 ...

    EntIM(聊呗)

    EntIM,又称为“聊呗”,是一款功能丰富的即时通讯应用源码,旨在提供全面的视频、语音和异步聊天功能。这款源码的亮点在于它的高度可定制性,用户可以根据自身需求更改数据源并进行UI界面的个性化设计,使之适应...

    聊一聊C语言变量

    - 内存泄漏:如果不释放动态分配的内存,这部分内存将不会被回收,久而久之会导致程序占用的内存不断增加,最终可能导致系统资源耗尽。 - 未初始化的内存:动态分配的内存不会自动初始化,它的初始值可能是任意的,...

    6.23直播 狂神聊汇编1

    6. **函数编写**:在汇编中,函数的实现涉及堆栈平衡,确保在函数调用前后,堆栈的使用保持一致,防止内存泄漏和错误。 7. **机器语言与汇编语言的关系**:机器语言是计算机直接执行的二进制代码,而汇编语言是机器...

    一份超级详细的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中的底层数据...

Global site tag (gtag.js) - Google Analytics