内存泄露是指无用对象(再也不使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而形成的内存空间的浪费称为内存泄露。内存泄露有时不严重且不易察觉,这样开发者就不知道存在内存泄露,但有时也会很严重会提示你Out of memory
。java
长生命周期的对象持有短生命周期对象的引用就极可能发生内存泄露,尽管短生命周期对象已经再也不须要,可是由于长生命周期对象持有它的引用而致使不能被回收,这就是java中内存泄露的发生场景git
只有一个,那就是虚拟机占用内存太高,致使OOM
(内存溢出),程序出错。对于Android
应用来讲,就是你的用户打开一个Activity
,使用完以后关闭它,内存泄露;又打开,又关闭,又泄露;几回以后,程序占用内存超过系统限制FC
。github
Android
手机给应用分配的内存一般是8兆左右,若是处理内存处理不当很容易形成OutOfMemoryError
数据库
OutOfMemoryError
主要由如下几种状况形成:缓存
数据库Cursor
没关。
当咱们操做完数据库后,必定要调用close()
释放资源。ide
构造Adapter
没有使用缓存ContentView
。函数
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder vHolder = null; //若是convertView对象为空则建立新对象,不为空则复用 if (convertView == null) { convertView = inflater.inflate(..., null); // 建立 ViewHodler 对象 vHolder = new ViewHolder(); vHolder.img= (ImageView) convertView.findViewById(...); vHolder.tv= (TextView) convertView .findViewById(...); // 将ViewHodler保存到Tag中 convertView.setTag(vHolder); } else { //当convertView不为空时,经过getTag()获得View vHolder = (ViewHolder) convertView.getTag(); } // 给对象赋值,修改显示的值 vHolder.img.setImageBitmap(...); vHolder.tv.setText(...); return convertView; } static class ViewHolder { TextView tv; ImageView img; }
未取消注册广播接收者registerReceiver()
和unregisterReceiver()
要成对出现,一般须要在Activity
的onDestory()
方法去取消注册广播接收者。post
IO流未关闭 注意用完后及时关闭ui
Bitmap使用后未调用recycle()。this
Context泄漏。 这是一个很隐晦的OutOfMemoryError的状况。先看一个Android官网提供的例子:
private static Drawable sBackground; @Override protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); if (sBackground == null) { sBackground = getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground); setContentView(label); }
这段代码效率很快,但同时又是极其错误的:Drawable
拥有一个TextView
的引用,而TextView
又拥有Activity
(Context类型)的引用,Drawable
拥有了更多的对象引用。即便Activity
被销毁,内存仍然不会被释放。
另外,对Context的引用超过它自己的生命周期,也会致使Context泄漏。因此尽可能使用Application这种Context类型。因此若是打算保存一个长时间的对象时,要使用getApplicationContext()
。 最近遇到一种状况引发了Context
泄漏,就是在Activity
销毁时,里面有其余线程没有停。
总结一下避免Contex
t泄漏应该注意的问题:
使用getApplicationContext()
类型。
注意对Context
的引用不要超过它自己的生命周期。
慎重的使用static
关键字。
Context
里若是有线程,必定要在onDestroy()
里及时停掉。
线程 线程也是形成内存泄露的一个重要的源头。线程产生内存泄露的主要缘由在于线程生命周期的不可控。咱们来考虑下面一段代码。
public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new MyThread().start(); } private class MyThread extends Thread{ @Override public void run() { super.run(); //耗时的操做 } } }
假设MyThread
的run
函数是一个很费时的操做,当调用finish
的时候Activity
会销毁掉吗?
事实上因为咱们的线程是Activity
的内部类,因此MyThread
中保存了Activity
的一个引用,当MyThread
的run
函数没有结束时,MyThread
是不会被销毁的,所以它所引用的老的Activity
也不会被销毁,所以就出现了内存泄露的问题。
Handler的使用,在Activity退出的时候注意移除(尤为是循环的时候)
public class ThreadDemo extends Activity { private static final String TAG = "ThreadDemo"; private int count = 0; private Handler mHandler = new Handler(); private Runnable mRunnable = new Runnable() { public void run() { //为了方便 查看,咱们用Log打印出来 Log.e(TAG, Thread.currentThread().getName() + " " +count); //每2秒执行一次 mHandler.postDelayed(mRunnable, 2000); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //经过Handler启动线程 mHandler.post(mRunnable); } }//因此咱们在应用退出时,要将线程销毁,咱们只要在Activity中的,onDestory()方法处理一下就OK了,以下代码所示:@Override protected void onDestroy() { mHandler.removeCallbacks(mRunnable); super.onDestroy(); }