内存泄漏:进程中某些对象已经没有使用价值了,但是它们却可以直接或间接地引用到,导致无法被GC回收。无用的对象占据着内存空间,使得实际可使用内存变小,从而导致内存泄漏了。
内存溢出(OOM):程序在申请内存时,没有足够的内存空间供其使用;内存泄漏是导致内存溢出的主要原因之一;
内存泄露的原因主要就是该关闭的资源对象没有即使释放;
1.单例造成的内存泄露
单例的特点是其生命周期与application保持一致
大概大多数的单例都是像这么写的吧
<code>
public class MyTest {
public static MyTest mTest;
private Context mContext;
private MyTest (Context context) {
mContext = context;
}
public static synchronized Test getInstance(Context context) {
if (mTest == null) {
mTest = new MyTest(context);
}
return mTest;
}
}
</code>
①如果传入的是 Activity 的 Context,当这个 Context 所对应的 Activity 退出时,由于该 Context 的引用被单例对象所持有,其生命周期等于整个应用程序的生命周期,所以当前 Activity 退出时它的内存并不会被回收,从而导致了内存泄露;
②当我们传入的是Application的Context的时候,单例的生命周期就和Application的一样长,因为Application的生命周期是贯穿整个程序的,所以MyTest类持有它的引用,也不会造成内存泄露问题。
所以当我们能用Application Context代替的,尽量用Application Context。
2.Bitmap使用不当
Bitmap是一个极容易消耗内存的对象,用完之后要及时回收;
当我们展示图片区域很小的时候,需要对图片进行压缩及降低像素或者加载缩略图等;
运用Glide加载图片的时候,ImageView的scaleType设置不当会导致OOM,当设置为我们fitXY时,Glide不会进行缩放,会以全分辨率加载,所以尽量不要设置为fitXY。
3.Handler造成的内存泄漏
非static的handler会持有activity的引用,而如果handler没有处理完成工作的时候,我们调用finish,则activity不能释放,这个时候就会出现内存泄漏。
平常我用handler是这样使用的:
<code>
public class MainActivity extends AppCompatActivity {
...
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
}
</code>
但是这样会造成内存泄漏,在Java中在内部创建对象之后会隐式的持有外部对象,也就是说new Handler()之后Handler对象对Activity就有了一个持有,那么此时finish掉Activity的话是没办法回收的。这就造成了内存泄漏。
正确使用handler的姿势应该是这样的:
<code>
static class MyHandler extends Handler {
private final WeakReference<Test> mActivity;
TestHandler(Test activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
final Test activity = mActivity.get();
if (activity == null || activity.isFinishing()) {
removeCallbacksAndMessages(null);
return;
}
}
}
</code>
4.匿名内部类造成的内存泄露
<code>
public class TestActivity extends Activity {
...
MyRunnable re1 = new MyRunable();
Runnable re2 = new Runnable() {
@Override
public void run() {
...
}
};
}
</code>
其中re2是匿名内部类,ref2的实现对象里面有个引用,这个引用指向TestActivity ,当前的TestActivity 实例会被re2持有,如果将这个引用再传入一个异步线程,此线程和此Acitivity生命周期不一致的时候,就造成了Activity的泄露。
5.资源性对象未关闭
File,Cursor,Stream,File,Cursor,Stream,BraodcastReceiver,ContentObserver,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。
6.Webview造成的内存泄露
在重复打开有WebView的页面时,你会发现,应用的内存会不断升高,销毁了之后也不会降下来,这样就出现了内存泄漏了;
使用Webview之后要activity的onDestroy方法中调用webView.removeAllViews()和webView.destroy();new WebView的时候需要传入ApplicationContext,如果传入Activity的Context的话,对内存的引用会一直被保持着;
7.静态变量造成的内存泄露
在 Activity 类中定义一个 static 变量,并将其指向一个运行中的 Activity 实例。如果在 Activity 的生命周期结束之前,没有清除这个引用,那它就会泄漏。由于 Activity 的类对象是静态的,一旦加载,就会在 APP 运行时一直常驻内存,如果类对象不卸载,其静态成员就不会被垃圾回收,应该尽量避免static成员变量引用资源耗费过多的实例;
Android的内存优化的建议:
1 对不用的对象显示置NULL;
2.使用更加轻量的数据结构;
3内存对象的重复利用,一些数据进行缓存;
4 注册监听及时注销;
5 优化布局,减少嵌套层次;
6 Listview的优化ContentView获取缓存的view,使用ViewHolder模。建议用recyclerview代替listview;
7 复用系统自带的资源,如颜色,图片,简单的布局,样式,接口,动画等;
- ━━━━━━神兽出没━━━━━━
- ┏┓ ┏┓
- ┏┛┻━━━┛┻┓
- ┃ ┃
- ┃ ━ ┃
- ┃ ┳┛ ┗┳ ┃
- ┃ ┃
- ┃ ┻ ┃
- ┃ ┃
- ┗━┓ ┏━┛
- ┃ ┃
- ┃ ┃
- ┃ ┗━━━┓
- ┃ ┣┓
- ┃ ┏┛
- ┗┓┓┏━┳┓┏┛
- ┃┫┫ ┃┫┫
- ┗┻┛ ┗┻┛
*━━━━━━━━━━━━━━━━