内存泄漏的学习
2016-05-06 15:12
148 查看
内存泄漏介绍
内存泄漏是针对与堆内存而言的。Java的内存管理就是对象的分配和释放。内存分配是由程序进行的,内存的释放是由GC完成。GC只能回收那些无用,且不被其他对象引用的对象们占用的空间。
从Main方法开始延伸,所有可以到达的对象都是有效对象,组成对象集合,这些不能被回收。其他的孤立对象则是GC回收的目标。
{ Object o = new Object(); }
局部变量的生命周期是在大括号结束。这时候,栈内的o被销毁,则 new Object() 这个对象不在被引用,成为孤立对象,会被GC回收。
所以,内存泄漏的根本原因是:堆内存中的长生命周期的对象持有短生命周期对象的强/软引用,尽管短生命周期对象已经不再需要,但因为长生命周期对象持有对他的引用而导致他不能被回收。
常见的内存泄漏
集合集合如果只有添加方法,没有删除方法,内存会被大量占用。如果集合是全局的,会造成内存只增不减。
单例
单例对象在被初始化后会在JVM整个生命周期中存在,如果单例持有了外部对象,会造成外部对象不能被回收,致使内存泄漏。
public class Test{ private static Test test; private Context context; private Test(Context context){ this.context = context; } public static Test getInstance(Context context){ if(test == null){ test = new Test(context); } return test; } }
如果传入的context是一个activity,会使activity一直存在于内存中,不能被释放。
Android中的各种组件
BroadCastReceiver,ContentObserver,Cursor等,在Regist后,记得在结束时调用unRegister或close(),并且,不要将Activity作为成员变量使用,例如上面单例的使用。如果一定需要,则记得使用 WeakReference。
非静态内部类
public class MainActivity extends AppCompatActivity { private static TestResource mResource = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(mResource == null){ mResource = new TestResource(); } //... } class TestResource { //... } }
外部类的静态成员mResource的生命周期是整个程序的运行时间,而内部类的对象默认持有对外部类对象的一个引用,所以会导致Activity无法得到释放。
可以将内部类定义为静态内部类,则可以将内部类和外部类的对象的关系切断,只与类有关。
线程造成的内存泄漏
因为线程的生命周期不可控,如果线程保存了对外部对象的引用,会造成外部对象的不可释放。
Handler造成的内存泄漏
如果handler发送的message没有被处理,那么MessageQueue将一直保留对handler,message的引用,而且handler与Activity的生命周期并不一致,可能会导致activity不能顺利释放。
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mLeakyHandler.postDelayed(new Runnable() { @Override public void run() { /* ... */ } }, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } }
以上代码,发送了延时的消息,这消息并未被处理时,该页面退出会导致该页面无法被回收。
注意事项
对activity的引用要考虑activity的生命周期,不过不能控制在其生命周期内,可以考虑用getApplicationContext(),避免activity长时间被占用。尽量不要在静态内部类使用非静态的成员变量,必须要用,也要在适当的时候将其置为空;也可以在静态内部类中使用弱引用来引用外部成员变量。
Handler持有的引用对象最好为弱引用,资源释放的时候可以清空handler中的消息。
线程处理耗时操作,在页面返回时即使取消。
相关文章推荐
- Java程序通过LDAP对用户进行登陆验证
- apache fluent 乱码
- android fragment传递参数_fragment之间传值的两种方法
- Codeforces Round #350 (Div. 2) C. Cinema 水题
- C# Graphics绘图 picBox
- Android LED控制
- 线程池的使用(二)
- Hadoop:Hadoop单机伪分布式的安装和配置
- Hadoop:Hadoop单机伪分布式的安装和配置
- Maven修改本地仓库路径
- Ucore_lab6
- DIV+CSS 清除浮动常用方法总结
- mysql更改最大打開文件數
- 迷宫问题
- 根据wsdl生成客户端Bean的两种方式
- spring事务管理
- 使用sklearn做特征工程
- Jayant Sinha:破产法案清零;将有助于提高商业便利
- [VMware]设置VM虚拟机随系统自动启动
- 解决umount.nfs: /data: device is busy 问题