内存泄漏
1. 定义:
(1)是指程序在申请内存后无法释放已申请的内存空间
(2)简单来说,就是发生内存泄漏是由于长周期对象持有对短周期对象的引用,使得短周期对象不能被回收。
(3)一次内存泄漏危害可以忽略,但堆积很严重,无论多少内存迟早被占光。
2.内存泄漏的原因
当一个对象不再被调用时,本应该被垃圾回收器回收,这时由于被另外一个正在使用的对象持有了想要被垃圾回收器回收的,从而导致该对象不能被回收,由于他不能被回收,所以他永远留在堆内存当中,造成内存泄漏
3.分类:--以发生的方式来分类,可分为4个类
(1) 常发性:
发生内存泄漏的代码被多次执行到了,每次被执行的时候会导致一块内存泄
(2)偶发性
发生内存泄漏的代码只有在某些特定的环境或操作过程下才会发生。
常发性和偶发性是相对的
对于特定的环境,偶发性也许就变成了常发性
](3)一次性
发生泄漏的代码只会被执行一次,或者由于算法的缺陷,导致总会有一块内存发生泄漏
(4) 隐式
程序在运行过程中不停的分配内存,但是知道结束的时候才释放内存
严格的说这里并没有发生内存泄漏,应为是最终程序释放了所有申请的内存
不及时释放内存也可能导致耗尽系统的所有内存
4. 内存泄漏后会有什么现象
(1) CPU资源耗尽:机器没有反应
(2) 进程id耗尽:没法创建新的进程了
(3) 硬盘耗尽
(4) 内存泄漏或者内存耗尽的时候,新的连接无法连接
内存泄漏是指堆内存的泄漏
堆内存:是指程序从堆中分配,大小任意的(内存块的带下可以在程序运行期决定),
但使用后必须显示释放的内存
5.内存泄漏的危害
(1) 从用户程度来看,内存泄漏本身不会产生什么危害也感觉不到他的存在
(2) 真正有危害的是内存泄漏的堆积,这会最终消耗系统所以的内存
(3) 隐士内存泄漏的危害性非常大,应为较之于常发性和偶发性内存泄漏更能被检测到
内存溢出
1.定义
内存溢出就是堆栈溢出
存储的数据超出了指定空间的大小,这时数据就会越界
指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存
内存的释放是由垃圾收集器(GarbageCollection,GC)完成的
简单的说,你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数据,出现溢出。
2.内存溢出的原因
JVM内存过小
内存中加载的数据量过于庞大
代码中存在死循环或循环产生过多重复的对象实体
集合类中有对对象的引用,使用完后未清空,使得JVM不能回收
3.内存溢出的解决办法
(1) 增加JVM的内存大小
(2).优化程序,释放垃圾
4.内存溢出和内存泄漏的区别
内存泄漏会最终导致内存溢出
相同的:都会导致应用程序运行出现问题,性能下降或挂起
不同点:
(1) 内存泄漏时导致内存溢出的原因之一,内存泄漏积累起来将导致内存溢出
(2) 内存泄漏可以通过代码来避免,内存溢出可以通过调整配置来减少发生频率,但无法彻底避免
内存溢出和内存泄漏的区别
(1) .java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内 存资源耗尽)
(2) java内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出
内存抖动
1.定义:
短时间内大量被对象创建,然后马上就会被释放,瞬间产生的对象会严重占用内存区域
内存抖动会引起频繁的GC,从而会使UI线程被频繁阻塞,导致画面卡顿
严重的时候会导致OOM
2.运用Studio来查看
(1).Studio提供了一个profile工具,可以帮助我们分析内存的情况,在studio上部有一个表盘的图标

(2).点击红框图标,然后就会运行当前项目,选中手机,在studio的底部就会出现一个Android Profile的工具项

(3).我们会看到有CPU,MEMORY,NETWORK三个选项,我们要监控的是内存,所以点击MEMORY

(4).在这张图中我们可以看到我们当前应用所占的内存total
GC手动垃圾回收,收集当前页面的内存情况并生成hprof文件,记录当前操作的内存情况
Gc是当前处于稳定状态,然后点击红色按钮开始记录内存状况,然后开始在手机上进行操作(一般这个时候会发现平稳的曲线开始波动)

(5)框内是我们当前记录的操作区间,当点击停止按钮的时候
在ClassName这个框内,会生成当前记录的操作区间(操作过程)的堆信息
曲线有一个向上的陡坡,说明我们的操作造成了大量的内存分配

(5).发现堆的信息是从大到小排列的,而第一条是系统的imageView,点击进去发现有大量的imageView对象,点击其中一个,右下角的框会显示该对象的具体位置信息
这样就知道内存抖动的地方了
在项目中什么时候会遇到内存泄漏
1.单利造成的内存泄漏
有时创建单例时如果我们需要Context对象,如果传入的是Application的Context那么不会有问题。如果传入的是Activity的Context对象,那么当Activity生命周期结束时,该Activity的引用依然被单例持有,所以不会被回收
2.Handler造成的内存泄漏
在Activity里面这样定义一个私有的Handler对象并初始化,这种创建Handler的方式会造成内存泄漏,由于mHandler是Handler的非静态匿名内部类的实例,所以它持有外部类Activity的引用,我们知道消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏。
网友评论