今天来复习一下有关内存泄露的知识,一个是把之前笔记整理一下,如有一些工具版本更新会写一些当下的使用介绍。另外会参考网上比较好的博文进行修正改进一些知识点
二、内存泄露、内存溢出、内存抖动首先我们必须对内存泄露有一个最简单的了解,就是一些对象有着有限的生命周期,当这些对象所要做的事情完成了,我们希望他们会被回收掉。但是如果有一系列对象对这个对象的引用,那么在我们期望这个对象生命周期结束的时候被GC回收的时候,它是不会被回收的,它还会占用内存,导致堆内存直升不降,这就造成了内存泄露。
指对象不再使用,本该被回收,却因为有其他正在使用的对象持有该对象的引用,而无法被GC回收,它占用内存,导致堆内存直升不降的情况。内存泄漏:
内存溢出:我们可以把app的堆内存空间想成了一个杯子,内存就是里面的水。当用户重复这个操作或者有多个不同Activity内存泄漏时,app运行一段时间堆内存超过系统规定的最大值 heapSize,杯子满了就会发生内存溢出(OOM)
内存抖动:是因为短时间内大量的对象被创建然后又被马上释放,瞬间产生大量的对象会严重占用内存区域,这块内存区域就是Young Generiation内存区域。当达到它的阀值,剩余空间不够的时候,就会触发GC(垃圾回收机制),这样刚产生的对象很快就被回收,每一次分配对象占用很少内存,但是它们叠加在一起就会造成Heap(堆内存)的压力,从而触发更多其他类型的GC,这个操作有可能会影响到帧率,并使得用户感知到性能问题。
内存溢出,内存抖动,内存泄漏这三者中这里面最严重的现象还是OOM也就是内存溢出,在开发过程中提到内存首先会想到内存溢出OOM,内存泄漏,然后才是内存抖动,内存抖动三者中严重程度比较轻。
内存溢出就是分配的内存不足以让你做有些操作,就是堆内存上有些内存没有被释放从而它会失去控制,造成程序使用的内存越来越少,导致系统运行速度减慢,严重程度下OOM,会造成整个程序的崩溃,所以为了提高APP的质量提高用户体验,我们必须避免与解决OOM。
三、LeakCanary 内存泄漏检测库-使用介绍内存泄露分析工具:使用 square公司的 LeakCanary 分析activity的内存泄露
1、github上搜索 LeakCanary 工具可在 github上搜索 LeakCanary 工具,可以看到 leakcanary 的源码:https://github.com/square/leakcanary
LeakCanary is a memory leak detection library for Android. LeakCanary是一个用于Android的内存泄漏检测库。
2、集成方式集成方式,点击链接:https://square.github.io/leakcanary/ ,如下图,
集成,目前最新版本 2.2 ,只需在 build.gradle 添加如下依赖:
// debug Implementation because LeakCanary should only run in debug builds.
// 调试实现,因为LeakCanary只应在调试生成中运行。
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'
That’s it, there is no code change needed! 就这样,不需要修改代码!
当然上面还有更新的提示:
To upgrade from LeakCanary 1.6, follow the upgrade guide. 要从LeakCanary 1.6升级,请遵循升级指南。
3、案例:非静态的内部类错误使用,导致 Activity内存泄露下面我们来看一下案例:
步骤1:新建一个 Module(模块/组件)我们可以在项目上,新建一个Module:File--->New--->New Module
然后一直默认。。。,完成如下:
步骤2:写主界面 MainActivity、布局activity_main布局activity_main
复习一下快捷键:option + enter
option + enter,会在 MainActivity 里面,自动生成方法: public void innerClass(View view) { }
主界面 MainActivity
package com.yyh.testleakdemo;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void innerClass(View view) {
startActivity( new Intent(MainActivity.this, InnerClassActivity.class));
}
}
步骤3:写业务逻辑:InnerClassActivity
子线程执行耗时操作
package com.yyh.testleakdemo;
import android.os.Bundle;
import android.os.SystemClock;
import androidx.appcompat.app.AppCompatActivity;
public class InnerClassActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inner_class);
new Thread(new Runnable() {
@Override
public void run() {
//模拟耗时操作
SystemClock.sleep(100*1000);
}
}).start();
}
}
4、效果展示
在夜神模拟器上,运行Module模块:testleakdemo
点击 Button跳转到一个 Activity,执行耗时线程操作,然后点击返回按钮 Activity退出,
InnerClassActivity 里面的耗时线程操作还没执行完,然后我们可以看到 LeakCanary 工具有内存泄露的相关提示
5、分析小结、解决方式分析小结
在Activity中启动子线程,子线程执行耗时操作,但是当Activity退出的时候,如果线程的任务还没执行完,那么该线程对象就不会死掉,该线程由于是Activity的内部对象,因此对外部类(Activity)有一个隐式的强引用,从而导致Activity也无法被GC回收掉,最后导致Activity一定时间的泄露。
解决方式
解决该泄露的方式:就是我们应该谨慎在Activity中开辟耗时的子线程,如果使用了那么也应该保证当Activity销毁的时候,将线程的任务退出。或者我们可以自定义一个静态的类继承Thread,然后再使用。因为只有非静态的内部类对象才会对外部类有隐式的强引用。
四、其他square公司,对我们 android来说,是一个大名鼎鼎的公司,它开源了相当多的开源框架。
比如说:LeakCanary(内存泄漏检测库)、OKHttp(网络请求库)、Picasso(图片库)、Retrofit(网络请求接口的封装)
square开源官网:https://square.github.io/#android
然后写博文的时候,偶然看到这篇博文,这哥们挺逗的