赞
踩
内存空间使用完毕后没有被回收,就会导致内存泄漏。虽然Java有垃圾回收机制,但是Java中任然存在很多造成内存泄漏的代码逻辑,垃圾回收器会回收掉大部分的内存空间,但是有一些内存空间还保持着引用,但是在逻辑上已经不会再用到的对象,这时候垃圾回收器就很无能为力,不能回收它们。
比如:
忘记释放分配的内存;
应用不需要这个对象了,但是却没有释放这个对象的引用;
强引用持有的对象,垃圾回收器是无法回收这个对象;
持有对象生命周期过长,导致无法回收;
图中的每个圆点都代表对象的内存资源,箭头代表可达路径。当圆点与GC Roots(Garbage Collection Roots)存在可达路径时,就表示当前资源正在被引用,虚拟机是无法对其进行回收的(如图中的黄色圆点),反过来,如果圆点与GC Roots不存在可达路径,则说明这个对象的内存空间不被引用,虚拟机可以将其回收掉。
Android(Java)平台的内存泄漏是指没用的对象资源与GC Roots之间保持可达路径,导致系统无法进行回收。
`
例如Activity的Context,它包含大量的内存引用,一旦泄漏了Context,也就意味着泄漏它指向的所有对象。
static Activity activity; //这种代码要避免
public class Singleton { private static Singleton instance; private Context mContext; private Singleton(Context context){ this.mContext = context; } public static Singleton getInstance(Context context){ if (instance == null){ synchronized (Singleton.class){ if (instance == null){ instance = new Singleton(context); } } } return instance; } }
在调用Singleton的getInstance()方法时传入了Activity,那么当instance没有释放的时,这个Activity会一直存在,导致内存泄漏。解决方法:
可以将new Singleton(context)改为new Singleton(context.getApplicationContext())即可,
这样便和传入的Activity没关系了。
1.将内部类变成静态内部类;
2.如果有强引用的Activity属性,则将该属性的引用方式改为弱引用;
3.在业务允许的情况下,当Activity执行onDestory时,结束这些耗时任务;
静态内部类不需要外部类的实例,可以通过外部类 . 静态内部类使用。
//这儿发生泄漏
public void test() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
解决办法:
//加上static,变成静态匿名内部类
public static void test() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
内部类引起内存泄漏的原因
https://blog.csdn.net/qq_22706515/article/details/51321718
5. Anonymous Classes
匿名类也维护了外部类的引用。当你在匿名类中执行耗时任务时,如果用户退出,会导致匿名类持有的Activity实例不会被垃圾回收器回收,直到异步任务结束。
6. Handler
handler中,Runnable内部类会持有外部类的隐式引用,被传递到Handler的消息队列MessageQueue中,在Message消息没有被处理之前,Activity实例不会被销毁了,于是导致内存泄漏。解决办法:
1.可以把Handler类放在单独的类文件中,或者使用静态内部类便可以避免泄露;
2.如果想在Handler内部去调用所在的Activity,那么可以在handler内部使用弱引用的方式去指向所在Activity.使用Static + WeakReference的方式来达到断开Handler与Activity之间存在引用关系的目的.
3.在界面销毁是,释放handler资源
@Override
protected void doOnDestroy() {
super.doOnDestroy();
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
}
mHandler = null;
mRenderCallback = null;
}
Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后在设置为null
我们经常把一些对象的引用加入到集合中,但我们不需要改对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static,那情况就更加严重了。解决方法:
在Activity退出之前,将集合里的东西clear,然后置为null,再退出程序。
这种Android内存泄漏比Java的内存泄漏还要严重,因为其他一些Android程序可能引用系统的Android程序的对象(如注册机制)。即使Android程序已经结束,但是别的应用程序仍然还有对Android程序的某个对象的引用,也会造成内存泄漏。解决方法:
1.使用ApplicationContext代替ActivityContext;
2.在Activity执行onDestory时,调用反注册;
资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。而不是等待GC来处理。
因为Bitmap占用的内存实在是太多了,特别是分辨率大的图片,如果要显示多张那问题就更显著了。Android分配给Bitmap的大小只有8M。解决方法:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来的四分之一
//软引用
SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap);
//回收操作
if(bitmap != null) {
if(bitmap.get() != null && !bitmap.get().isRecycled()){
bitmap.get().recycle();
bitmap = null;
}
}
解决方法:
@Override protected void onDestroy() { if( mWebView!=null) { // 如果先调用destroy()方法,则会命中if (isDestroyed()) return;这一行代码,需要先onDetachedFromWindow(),再 // destory() ViewParent parent = mWebView.getParent(); if (parent != null) { ((ViewGroup) parent).removeView(mWebView); } mWebView.stopLoading(); // 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错 mWebView.getSettings().setJavaScriptEnabled(false); mWebView.clearHistory(); mWebView.clearView(); mWebView.removeAllViews(); mWebView.destroy(); } super.on Destroy(); }
Lint 是 Android Studio 自带的工具, Analyze -> Inspect Code 然后选择想要扫面的区域即可
对可能引起泄漏的编码,Lint 都会进行温馨提示:
Square 公司出品的内存分析工具,官方地址如下:https://github.com/square/leakcanary/LeakCanary 需要在项目代码中集成。当内存泄漏发生时,LeakCanary 会弹窗提示并生成对应的堆存储信息记录。
打开Android Studio,编译代码,在模拟器或者真机上运行App,然后点击(如下),进入如下界面
点击MEMORY,进入
AndroidStudio3.0最新 Android Profiler分析器(cpu memory network 分析器)
如上图所示,内存分析器的默认视图包括以下内容:
① 强制执行垃圾收集事件的按钮。
② 捕获堆转储的按钮。
③ 记录内存分配的按钮。
④ 放大时间线的按钮。
⑤ 跳转到实时内存数据的按钮。
⑥ 事件时间线显示活动状态、用户输入事件和屏幕旋转事件。
⑦ 内存使用时间表,其中包括以下内容:
每个内存类别使用多少内存的堆栈图,如左边的y轴和顶部的颜色键所示。
虚线表示已分配对象的数量,如右侧y轴所示。
每个垃圾收集事件的图标。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。