赞
踩
Android开发,内存优化是一个很重要的问题,今天就对这方面的问题,做一个较为详细的介绍
在讲内存优化之前,先要将内存环境问题说清楚
java中内存环境分为三种
栈:用于存放基本数据类型和对象的引用
堆:用于存放创建出来的对象或者数组,由GC管理,被所有线程共享
方法区:也叫静态区,包含了静态变量和class对象,被所有线程共享
内存泄漏的原因,具体可以分为下面两种情况
1,当一个对象已经不需要使用时,准备被回收时,被另外一个对象持有了引用导致无法回收
2,有些对象只有有限的生命周期,在生命周期本该结束时,仍被引用。
内存泄漏的累积,会导致内存溢出。即OOM
接下来讲几种常见的内存泄漏情况和处理方法:
先来看以下代码,是一个简单的单例模式
- public class SingerDemo {
-
- private Context context;
- private static SingerDemo instance;
-
- private SingerDemo(Context context) {
- this.context = context;
- }
-
- public static SingerDemo getInstance(Context context) {
- if (instance == null) {
- instance = new SingerDemo(context);
- }
- return instance;
- }
- }
在单例的构造方法里面,会传入一个Context对象
如果我们传入的是Activity的Context,在Activity关闭时,这个单例的对象仍然持有Activity的引用
从而导致内存泄漏
这个解决的方法,就是在单例的构造方法里面做处理
使用getApplicationContext()获取到应用的Context
具体代码如下
- private SingerDemo(Context context) {
- // this.context = context;
- this.context = context.getApplicationContext();
- }
这个例子也告诉我们,在使用Context的时候,要注意区分情况。
再来看下面的代码
- public class MainActivity extends AppCompatActivity {
- private static MainClass mainClass = null;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- if (mainClass == null) {
- mainClass = new MainClass();
- }
- }
-
- private class MainClass {
-
- }
- }
这种情况下,非静态的内部类MainClass默认持有了MainActivity的引用
从而导致他的静态实例对象一直持有Activity的引用
在Activity关闭时无法释放
从而导致MainClass无法被内存回收,导致内存泄漏
解决方法
把内部类改成静态内部类即可
Handler的生命周期和Activity的生命周期是不一致的,
所以Activity关闭的时候
Handler可能还存在内存
看下面这个例子
- public class MainActivity extends AppCompatActivity {
-
- private final Handler myhandler = new Handler(Context context) {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- myhandler.postDelayed(new Runnable() {
- @Override
- public void run() {
-
- }
- }, 1000 * 60 * 10);
- }
-
- }
当Handler延迟执行消息的时候,把Activity关闭
这个时候Handler持有了Activity的对象
导致了内存泄漏
解决的方法有两种,第一种
就是在Activity关闭时,remove掉Handler的消息
removeMessages:移除单个message
removeCallbacksAndMessages:移除全部message和回调
另外一种办法
1,将handler声明为静态的
2,通过弱引用的方式引入Activity,
对相关方法和View进行操作
代码如下:
- private static class MyHandler extends Handler {
- private WeakReference<MainActivity> mWeakReference;
-
- public MyHandler(MainActivity activity) {
- mWeakReference = new WeakReference<>(activity);
- }
-
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- MainActivity mainActivity = mWeakReference.get();
- switch (msg.what) {
- case 0x001:
- if (mainActivity != null) {
- mainActivity.mTextView.setText(msg.obj + "");
- }
- break;
- default:
- break;
- }
- }
- }
线程导致的内存泄漏,处理方式和Handler一样
将Thread和Runnable
都声明为静态的
用弱引用的方式获得Activity对象
或者在合适的生命周期,
去结束这个线程
Webview造成内存泄漏的原因有很多种
有时候需要移动端和网页端对应处理
这里提供一种解决方法
1,将Webview所处的Activity放在一个单独的进程当中
在Activity的配置清单里添加android:process=""属性即可
process属性的值即是你的进程的名字
2,关闭Activity时,调用下面这个方法,去杀掉这个进程即可
android.os.Process.killProcess(android.os.Process.myPid());
更多解决方式,可以参考这篇文章
最后分享几个关于内存优化的点
1,频繁的字符串拼接使用StringBuilder代替String
2,ArrayMap,Sparse代替HashMap
3,不要频繁地创建和回收大量对象,避免内存抖动
因为在调用GC的过程中,会停住其他进程
一旦要处理的对象过多,就会造成UI卡顿等问题
4,复用系统自带的资源,ListView的item复用等
5,避免在onDraw方法里创建对象
6,及时关闭Cursor对象
7,注册和取消注册要成对出现。如广播的注册和取消注册
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。