Android造成内存泄漏原因及解决方案

开发app中对内存的使用,一定是大家最关心的问题之一,因为内存的使用直接影响到app的性能。

内存使用中内存泄漏是开发Android应用中常见的,Android中可以使用LeakCanary来检测内存泄漏。

 

那么什么是内存泄漏?

内存泄漏简单解释就是:完全无用的对象,无法被被GC回收的现象就是内存泄漏。

 

内存泄漏会造成什么问题呢?

每个app可分配的内存是有限的,内存泄漏就会占有一块内存,过多的内存泄漏就会导致内存超出app可用的内存,导致内存溢出,app就奔溃了(引发Out Of Memory)。

 

接下来我们带着三个问题来分析下内存泄漏:

1.经常会出现内存泄漏的地方有哪些?

2.为什么会出现?

3.如何避免内存泄漏?

 

一.单例模式造成的内存泄漏:

public class Signleton {
    private static Signleton mSignleton;
    private Context mContext;
    private Signleton(Context context){
        this.mContext = context;
    }
    public static Signleton getInstance(Context context){
        if (mSignleton == null){
            mSignleton = new Signleton(context);
        }

        return mSignleton;
    }
}

这里为什么会出现内存泄漏呢?

     因为单例模式的生命周期和应用程序是一样长的,所以当我们在一个activity中调用这个单例,传入activity作为context,单例就持有了这个activity的引用,而当我们退出这个activity时,由于单例的生命周期是同应用程序一样长,所以这个单例还持有activity的引用,这个activity对象就不会被回收,这时就造成了内存泄漏。

如何解决:

private Signleton(Context context){
    this.context = context.getApplicationContext();
}

这里我们改成不管传入的context是activity还是其他的都转换为整个应用程序的context,这样生命周期就和单例一样长,就避免了内存泄漏。

 

二.非静态内部类造成的内存泄漏:  

private final String TAG = "DemoActivity";
private static Interior mInterior;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    if (mInterior == null){
        mInterior = new Interior();
    }
}
class Interior{}

这里为什么会出现内存泄漏呢?

这个activity中有一个非静态内部类,因为非静态内部类中隐式持有外部类的引用,所以内部类Interior中就持有activity的引用,

例子中静态变量mInterior的生命周期是和应用程序一样长的,而该静态变量中又持有activity的引用,所以到activity销毁时,回收activity的时候无法被回收,就出现了内存泄漏。

如何解决:

static class Interior{

}

把该非静态内部类改成静态内部类就可以了(因为静态内部类不会持有外部的引用)。

 

三.Handler造成的内存泄漏:

private void toHandler(){
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            tvTitle.setText("hello");
        }
    },1000);
}

这里为什么会出现内存泄漏呢?

这段代码中有两个方面会造成内存泄漏:

1.Runnable是匿名内部类,持有Activity的 TextView会造成内存泄漏。

2.TextView持有Activity 的强引用,这样也会造成内存泄漏。

因为handler的消息机制,当Activity销毁,handler中还有为处理的Message时就会持有activity的引用从而导致无法被回收,出现内存泄漏。

如何解决:

方法1:改成静态内部类+弱引用

private static class DemoRunnable implements Runnable{
    private WeakReference<TextView> wTextView;
    protected DemoRunnable(TextView textView){
        wTextView = new WeakReference<TextView>(textView);
    }
    @Override
    public void run() {
        wTextView.get().setText("hello");
    }

}

方法2:在Activity的onDestory中移除mHandler的所有Message

@Override
protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
}

四.线程造成的内存泄漏:

线程的内存泄漏同Handler一样也是匿名内部类Runnable造成的,解决方式同handler方法1一样。

五.资源未关闭造成的内存泄漏:

主要使用的资源:

1.BraodcastReceiver

2.ContentObserver

3.File

4.Cursor

5.Stream

6.Bitmap

这些资源的使用都需要在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,从而造成内存泄漏。

发布了97 篇原创文章 · 获赞 201 · 访问量 21万+
展开阅读全文

EMUI5.0 Android7.0中开发遇到内存泄漏

02-10

com.zxsd.shoppingguide.activity.AggregationEntryActivity has leaked: GC ROOT static android.gestureboost.GestureBoostManager.sGestureBoostManager references android.gestureboost.GestureBoostManager.mContext leaks com.zxsd.shoppingguide.activity.AggregationEntryActivity instance Retaining: 4.9 KB. Reference Key: def072d8-5909-4709-9365-9a244a488e02 Device: HUAWEI honor FRD-AL10 FRD-AL10 Android Version: 7.0 API: 24 LeakCanary: 1.5 00f37f5 Durations: watch=5011ms, gc=173ms, heap dump=1862ms, analysis=103468ms Details: Class android.gestureboost.GestureBoostManager static sGestureBoostManager = android.gestureboost.GestureBoostManager@3172306 (0x12e88e50) static SWITCH_GESTURE_BOOST = 4 static $classOverhead = byte[652]@318563329 (0x12fce401) static TAG = java.lang.String@1896298 (0x71073638) static GESTURE_BOOST_CODE = 10001 static RMS_EXT_CODE_BASE = 10000 Instance of android.gestureboost.GestureBoostManager static sGestureBoostManager = android.gestureboost.GestureBoostManager@3172306 (0x12e88e50) static SWITCH_GESTURE_BOOST = 4 static $classOverhead = byte[652]@318563329 (0x12fce401) static TAG = java.lang.String@1896298 (0x71073638) static GESTURE_BOOST_CODE = 10001 static RMS_EXT_CODE_BASE = 10000 mAwareService = null mContext = com.zxsd.shoppingguide.activity.AggregationEntryActivity@3151232 (0x12c86600) mGestureBoostflag = false shadow$klass = android.gestureboost.GestureBoostManager shadow$monitor = 0 Instance of com.zxsd.shoppingguide.activity.AggregationEntryActivity static $change = null static $classOverhead = byte[4544]@316317697 (0x12daa001) static serialVersionUID = 0 appBarLayout = android.support.design.widget.AppBarLayout@3208130 (0x131f3800) btnLeft = android.support.v7.widget.AppCompatTextView@3211796 (0x1324d000) btnRight = android.support.v7.widget.AppCompatTextView@3212390 (0x1325b800) btnRightTwo = android.support.v7.widget.AppCompatTextView@3212267 (0x13258800) bundle = android.os.Bundle@3205945 (0x131be280) container = android.widget.FrameLayout@3214438 (0x1328d800) fragment = com.zxsd.shoppingguide.fragment.AggregationEntryFragment@3151228 (0x12c864c0) imgBack = android.support.v7.widget.AppCompatImageButton@3211827 (0x1324dc00) imgMore = android.support.v7.widget.AppCompatImageButton@3212369 (0x1325b000) layoutId = 2130968603 toolbar = android.support.v7.widget.Toolbar@3211560 (0x13247400) toolbarTitle = android.support.v7.widget.AppCompatTextView@3214479 (0x1328e800) mDelegate = android.support.v7.app.AppCompatDelegateImplN@3148888 (0x12c4d280) mEatKeyUpEvent = false mResources = null mThemeId = 2131361857 mCreated = true mFragments = android.support.v4.app.FragmentController@3164159 (0x12dc1fc0) mHandler = android.support.v4.app.FragmentActivity$1@319517120 (0x130b71c0) mNextCandidateRequestIndex = 0 mOptionsMenuInvalidated = false mPendingFragmentActivityResults = android.support.v4.util.SparseArrayCompat@3205947 (0x131be340) mReallyStopped = true mRequestedPermissionsFromFragment = false mResumed = false mRetaining = false mStopped = true mStartedActivityFromFragment = false mStartedIntentSenderFromFragment = false mExtraDataMap = android.support.v4.util.SimpleArrayMap@3204282 (0x131958c8) mActionBar = null mActionModeTypeStarting = 0 mActivityInfo = android.content.pm.ActivityInfo@3148902 (0x12c4d820) mActivityTransitionState = android.app.ActivityTransitionState@3191331 (0x130595b8) mApplication = com.zxsd.shoppingguide.base.App@3146104 (0x12c09308) mCalled = true mChangeCanvasToTranslucent = false mChangingConfigurations = false mComponent = android.content.ComponentName@3162928 (0x12da3f00) mConfigChangeFlags = 0 mCurrentConfig = android.content.res.Configuration@3158405 (0x12d35848) mCustActivity = android.app.HwCustActivityImpl@3204282 (0x131958f8) mDecor = null mDefaultKeyMode = 0 mDefaultKeySsb = null mDestroyed = true mDoReportFullyDrawn = false mEatKeyUpEvent = false mEmbeddedID = null mEnableDefaultActionBarUp = false mEnterTransitionListener = android.app.SharedElementCallback$1@1903589792 (0x717679a0) mExitTransitionListener = android.app.SharedElementCallback$1@1903589792 (0x717679a0) mFinished = true mFragments = android.app.FragmentController@3153430 (0x12cbc0d0) mHandler = android.os.Handler@3195173 (0x130b72c0) mHasCurrentPermissionsRequest = false mIdent = 132658027 mInstanceTracker = android.os.StrictMode$InstanceTracker@315343040 (0x12cbc0c0) mInstrumentation = android.app.Instrumentation@3148126 (0x12c3a8f8) mIntent = android.content.Intent@3168869 (0x12e34fc0) mIsFullFlag = false mLastNonConfigurationInstances = null mMainThread = android.app.ActivityThread@3147206 (0x12c24160) mManagedCursors = java.util.ArrayList@3204284 (0x131959a0) mManagedDialogs = null mMenuInflater = null mParent = null mReferrer = java.lang.String@3168862 (0x12e34cc0) mResultCode = 0 mResultData = null mResumed = false mSearchEvent = null mSearchManager = null mStartedActivity = false mStopped = true mTaskDescription = android.app.ActivityManager$TaskDescription@319517344 (0x130b72a0) mTemporaryPause = false mTitle = java.lang.String@1894097 (0x70e5a400) mTitleColor = 0 mTitleReady = true mToken = android.os.BinderProxy@3197227 (0x130e9500) mTranslucentCallback = null mUiThread = java.lang.Thread@2021072 (0x78771dd0) mVisibleBehind = false mVisibleFromClient = true mVisibleFromServer = true mVoiceInteractor = null mWindow = com.android.internal.policy.HwPhoneWindow@3167633 (0x12e16ce0) mWindowAdded = true mWindowManager = android.view.WindowManagerImpl@3198605 (0x1310af60) mInflater = com.android.internal.policy.HwPhoneLayoutInflater@3170012 (0x12e50e20) mOverrideConfiguration = null mResources = android.content.res.HwResources@3164745 (0x12dd04c0) mTheme = android.content.res.Resources$Theme@316415648 (0x12dc1ea0) mThemeResource = 2131361857 mBase = android.app.ContextImpl@3148388 (0x12c40f20) shadow$klass = com.zxsd.shoppingguide.activity.AggregationEntryActivity shadow$monitor = 1073743756 Excluded Refs: Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always) Thread:FinalizerWatchdogDaemon (always) Thread:main (always) Thread:LeakCanary-Heap-Dump (always) Class:java.lang.ref.WeakReference (always) Class:java.lang.ref.SoftReference (always) Class:java.lang.ref.PhantomReference (always) Class:java.lang.ref.Finalizer (always) Class:java.lang.ref.FinalizerReference (always) ![图片说明](https://img-ask.csdn.net/upload/201702/10/1486711588_136805.png) 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览