首页 > 系统 > Android > 正文

Android 性能优化之——内存优化

2019-11-06 09:49:05
字体:
来源:转载
供稿:网友

内存溢出(OOM)

应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用Crash

内存泄漏

当一个对象已经不需要再使用了,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中,导致内存泄漏

关系:

内存泄漏是造成内存溢出的主要原因之一,因此在开发中应避免内存泄漏。

常见几种造成内存泄漏的案例:

一、单例造成的内存泄漏

单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。

/** * 1、传入的是application的Context:这将没有任何问题,因为单例的生命周期和Application的一样长 ; * 2、传入的是Activity的Context:当这个Context所对应的Activity退出时,由于该Context和Activity * 的生命周期一样长(Activity间接继承于Context),所以当前Activity退出时它的内存并不会被回收, * 因为单例对象持有该Activity的引用,从而造成内存泄漏。 */public class AppManager { PRivate static AppManager instance; private Context mContext; private AppManager(Context context){ mContext = context; } public static AppManager getInstance(Context context) { if (instance == null) { synchronized (instance){ if(instance!=null){ instance = new AppManager(context); } } } return instance; }}

二、非静态内部类创建静态实例造成的内存泄漏

非静态的内部类会持有外部类的一个隐式引用

/** * 非静态内部类持有外部类的隐式引用 * 而用该非静态内部类创建 静态的实例 * 该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用 */public class WorkActivity extends JYActivity{ private static PersonBean person = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(person!=null){ person = new PersonBean(); } //... } class PersonBean{ //... }}

三、Handler造成的内存泄漏

Handler的使用编码不规范即有可能造成内存泄漏

/** * 非静态内部类持有外部类的隐式引用 * 由于mHandler是Handler的非静态匿名内部类的实例,所以它持有外部类Activity的引用 * 消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时, * 消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用 * mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏 */public class WorkActivity extends JYActivity{ private TextView tvShow; private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); tvShow.setText(msg.arg1+"测试"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvShow = (TextView) this.findViewById(R.id.tv_item); loadData(); } private void loadData() { Message msg = mHandler.obtainMessage(); mHandler.sendMessage(msg); }}

正确写法

/** * 非静态内部类持有外部类的隐式引用 * 创建静态的内部类,弱引用Activity,从而可以持有Activity实例来做更新UI操作 * 在onDestroy方法中移除消息队列中的消息,从而更好的避免了内存泄漏 * */public class WorkActivity extends JYActivity{ private TextView tvShow; private MyHandler mHandler = new MyHandler(this); public static class MyHandler extends Handler{ private WeakReference<Context> wrf; public MyHandler(Context context){ wrf = new WeakReference<Context>(context); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); WorkActivity temp = (WorkActivity) wrf.get(); if(temp!=null){ temp.tvShow.setText(msg+"msg"); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvShow = (TextView) this.findViewById(R.id.tv_item); loadData(); } private void loadData() { Message msg = mHandler.obtainMessage(); mHandler.sendMessage(msg); } @Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); }}

四、线程造成的内存泄漏

/** * 非静态内部类持有外部类的隐式引用 * 子线程内部类持有Activity的引用,当活动关闭时,子线程任务还没有执行完毕 * 导致Activity的内存资源无法回收,造成内存泄漏 */public class WorkActivity extends JYActivity{ private TextView tvShow; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvShow = (TextView) this.findViewById(R.id.tv_item); new Thread(new Runnable() { @Override public void run() { //...耗时操作 } }).start(); }}/** * 非静态内部类持有外部类的隐式引用 * 子线程内部类持有Activity的引用,当活动关闭时,子线程任务还没有执行完毕 * 导致Activity的内存资源无法回收,造成内存泄漏 */public class WorkActivity extends JYActivity{ private TextView tvShow; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvShow = (TextView) this.findViewById(R.id.tv_item); new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { //...耗时操作 return null; } }.execute(); }}
如何避免
/** * 非静态内部类持有外部类的隐式引用 * 定义静态内部类,避免内存泄漏 */public class WorkActivity extends JYActivity{ private TextView tvShow; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvShow = (TextView) this.findViewById(R.id.tv_item); new Thread(new MyRunnable()).start(); } static class MyRunnable implements Runnable{ @Override public void run() { //...耗时操作 } }}/** * 非静态内部类持有外部类的隐式引用 * 定义静态内部类,+ 若引用 避免内存泄漏 */public class WorkActivity extends JYActivity{ private TextView tvShow; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvShow = (TextView) this.findViewById(R.id.tv_item); new MyAsyncTask(this).execute(); } static class MyAsyncTask extends AsyncTask<Void, Void, Void> { private WeakReference<Context> weakReference; public MyAsyncTask(Context context) { weakReference = new WeakReference<>(context); } @Override protected Void doInBackground(Void... params) { //... 耗时操作 return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); MainActivity activity = (MainActivity) weakReference.get(); if (activity != null) { //... } } }}

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

对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。

六、属性动画为及时停在

属性动画未在onDestory中停止,造成动画一直播放下去(即使在界面上看不到动画效果),活动的view被动画持有,view持有Activity的引用,最终导致Activity无法释放,造成内存泄漏


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表