h5自适应网站源码,wordpress 改网站介绍,网站计划任务怎么做,智能建站系统开发1.什么是内存泄漏
2.内存泄漏造成什么影响
3.内存泄漏检测的工具有哪些
4.关于Leakcanary使用介绍
5.Leakcanary捕捉常见的内存泄漏及解决办法5.1 错误使用单例造成的内存泄漏
5.2 错误使用静态变量#xff0c;导致引用后无法销毁【工具类使用不当导致内存泄漏】
5.3 Handler造…1.什么是内存泄漏2.内存泄漏造成什么影响3.内存泄漏检测的工具有哪些4.关于Leakcanary使用介绍5.Leakcanary捕捉常见的内存泄漏及解决办法5.1 错误使用单例造成的内存泄漏5.2 错误使用静态变量导致引用后无法销毁【工具类使用不当导致内存泄漏】5.3 Handler造成的内存泄漏5.4 线程造成的内存泄漏5.5 由WebView引起的内存泄漏5.6 资源未关闭造成的内存泄漏5.7 未注销EventBus导致的内存泄漏5.8 静态集合使用不当导致的内存泄漏5.9 使用弱引用避免内存泄漏6.其他1.什么是内存泄漏一些对象有着有限的声明周期当这些对象所要做的事情完成了我们希望它们会被垃圾回收器回收掉。但是如果有一系列对这个对象的引用存在那么在我们期待这个对象生命周期结束时被垃圾回收器回收的时候它是不会被回收的。它还会占用内存这就造成了内存泄露。持续累加内存很快被耗尽。比如当Activity的onDestroy()方法被调用后Activity以及它涉及到的View和相关的Bitmap都应该被回收掉。但是如果有一个后台线程持有这个Activity的引用那么该Activity所占用的内存就不能被回收这最终将会导致内存耗尽引发OOM而让应用crash掉。2.内存泄漏会造成什么影响它是造成应用程序OOM的主要原因之一。由于android系统为每个应用程序分配的内存有限当一个应用中产生的内存泄漏比较多时就难免会导致应用所需要的内存超过这个系统分配的内存限额这就造成了内存溢出而导致应用Crash。3.内存泄漏检测的工具有哪些最常见的是Leakcanary4.关于Leakcanary使用介绍LeakCanary是Square开源框架是一个Android和Java的内存泄露检测库如果检测到某个 activity 有内存泄露LeakCanary 就是自动地显示一个通知所以可以把它理解为傻瓜式的内存泄露检测工具。通过它可以大幅度减少开发中遇到的oom问题大大提高APP的质量。集成:1. 添加依赖在你的项目的 build.gradle 文件中添加 LeakCanary 的依赖dependencies { debugImplementation com.squareup.leakcanary:leakcanary-android:2.7 // 如果需要在 release 版本中也检测内存泄漏可以添加以下依赖 releaseImplementation com.squareup.leakcanary:leakcanary-android-no-op:2.7 }2. 初始化在 Application 类的 onCreate 方法中初始化 LeakCanaryclass MyApplication : Application() { override fun onCreate() { super.onCreate() LeakCanary.initialize(this) } }3.配置 LeakCanary可选LeakCanary.config { //忽略特定的类 excludeObjectClasses(*arrayOf(java.lang.Class)) //忽略特定的引用链 excludeLeak(java.lang.Class) //自定义内存泄漏通知的图标 notificationIcon(R.drawable.your_icon) //更多配置... }4.分析结果保存到文件(可选)import android.content.Context; import com.squareup.leakcanary.LeakCanary; import com.squareup.leakcanary.OnHeapAnalyzedListener; import com.squareup.leakcanary.AnalysisResult; import com.squareup.leakcanary.HeapAnalysis; import java.io.File; import java.io.FileWriter; import java.io.IOException; public class CustomLeakListener implements OnHeapAnalyzedListener { private final Context context; public CustomLeakListener(Context context) { this.context context; } Override public void onHeapAnalyzed(HeapAnalysis heapAnalysis) { File outputFile new File(context.getExternalFilesDir(null), leak_analysis_result.txt); try (FileWriter writer new FileWriter(outputFile, true)) { writer.write(heapAnalysis.toString()); writer.write(\n\n); } catch (IOException e) { e.printStackTrace(); } } }5.Leakcanary捕捉常见的内存泄漏及解决办法5.1 错误使用单例造成的内存泄漏在平时开发中单例设计模式是我们经常使用的一种设计模式而在开发中单例经常需要持有Context对象如果持有的Context对象生命周期与单例生命周期更短时或导致Context无法被释放回收则有可能造成内存泄漏错误写法如下* 问题引起内存泄漏代码public class LoginManager { private static LoginManager mInstance; private Context mContext; private LoginManager(Context context) { this.mContext context; //修改代码**this.mContext context.getApplicationContext();** } public static LoginManager getInstance(Context context) { if (mInstance null) { synchronized (LoginManager.class) { if (mInstance null) { mInstance new LoginManager(context); } } } return mInstance; } public void dealData() {} }在一个Activity中调用的然后关闭该Activity则会出现内存泄漏。LoginManager.getInstance(this).dealData();报错如图:解决办法要保证Context和AppLication的生命周期一样修改后代码如下this.mContext context.getApplicationContext();原因分析创建单例对象并且在创建的时候需要传入一个Context对象而这时候如果我们使用Activity、Service等Context对象由于单例对象的生命周期与进程的生命周期相同会造成我们传入的Activity、Service对象无法被回收这时候就需要我们传入Application对象或者在方法中使用Application对象5.2 错误使用静态变量导致引用后无法销毁在平时开发中有时候我们创建了一个工具类。比如分享工具类十分方便多处调用因此使用静态方法是十分方便的。但是创建的对象建议不要全局化全局化的变量必须加上static。这样会引起内存泄漏。在Activity中引用后关闭该Activity会导致内存泄漏DoShareUtil.showFullScreenShareView(PNewsContentActivity.this, title, title, shareurl, logo);问题代码:报错如图:解决办法静态方法中创建对象或变量不要全局化全局化后的变量或者对象会导致内存泄漏popMenuView和popMenu都不要全局化**非静态内部类静态实例化**public class MyActivity extends AppCompatActivity { //静态成员变量 public static InnerClass innerClass null; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); innerClass new InnerClass(); } class InnerClass { public void doSomeThing() {} } }这里内部类InnerClass隐式的持有外部类MyActivity的引用而在MyActivity的onCreate方法中调用了。这样innerClass就会在MyActivity创建的时候是有了他的引用而innerClass是静态类型的不会被垃圾回收MyActivity在执行onDestory方法的时候由于被innerClass持有了引用而无法被回收所以这样MyActivity就总是被innerClass持有而无法回收造成内存泄露。5.3 Handler造成的内存泄漏【轮播图无限循环轮播一定要关闭否则内存泄漏】handler是工作线程与UI线程之间通讯的桥梁只是现在大量开源框架对其进行了封装我们这里模拟一种常见使用方式来模拟内存泄漏情形。public class MainActivity extends AppCompatActivity { private Handler mHandler new Handler(); private TextView mTextView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView (TextView) findViewById(R.id.text); //模拟内存泄露 mHandler.postDelayed(new Runnable() { Override public void run() { mTextView.setText(yangchong); } }, 2000); } }造成内存泄漏原因分析上述代码通过内部类的方式创建mHandler对象,此时mHandler会隐式地持有一个外部类对象引用这里就是MainActivity当执行postDelayed方法时该方法会将你的Handler装入一个Message并把这条Message推到MessageQueue中MessageQueue是在一个Looper线程中不断轮询处理消息那么当这个Activity退出时消息队列中还有未处理的消息或者正在处理消息而消息队列中的Message持有mHandler实例的引用mHandler又持有Activity的引用所以导致该Activity的内存资源无法及时回收引发内存泄漏。报错如图解决办法要想避免Handler引起内存泄漏问题需要我们在Activity关闭退出的时候的移除消息队列中所有消息和所有的Runnable。上述代码只需在onDestroy()函数中调用mHandler.removeCallbacksAndMessages(null);Override protected void onDestroy() { super.onDestroy(); if(handler!null){ handler.removeCallbacksAndMessages(null); handler null; } }5.4 线程造成的内存泄漏早时期的时候处理耗时操作多数都是采用ThreadHandler的方式后来逐步被AsyncTask取代直到现在采用RxJava的方式来处理异步。这里以AsyncTask为例可能大部分人都会这样处理一个耗时操作然后通知UI更新结果public class MainActivity extends AppCompatActivity { private AsyncTaskVoid, Void, Integer asyncTask; private TextView mTextView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView (TextView) findViewById(R.id.text); testAsyncTask(); finish(); } private void testAsyncTask() { asyncTask new AsyncTaskVoid, Void, Integer() { Override protected Integer doInBackground(Void... params) { int i 0; //模拟耗时操作 while (!isCancelled()) { i; if (i 1000000000) { break; } Log.e(LeakCanary, asyncTask---- i); } return i; } Override protected void onPostExecute(Integer integer) { super.onPostExecute(integer); mTextView.setText(String.valueOf(integer)); } }; asyncTask.execute(); } }造成内存泄漏原因分析在处理一个比较耗时的操作时可能还没处理结束MainActivity就执行了退出操作但是此时AsyncTask依然持有对MainActivity的引用就会导致MainActivity无法释放回收引发内存泄漏报错如图解决办法在使用AsyncTask时在Activity销毁时候也应该取消相应的任务AsyncTask.cancel()方法避免任务在后台执行浪费资源进而避免内存泄漏的发生private void destroyAsyncTask() { if (asyncTask ! null !asyncTask.isCancelled()) { asyncTask.cancel(true); } asyncTask null; } Override protected void onDestroy() { super.onDestroy(); destroyAsyncTask(); }5.5 由WebView引起的内存泄漏WebView解析网页时会申请Native堆内存用于保存页面元素当页面较复杂时会有很大的内存占用。如果页面包含图片内存占用会更严重。并且打开新页面时为了能快速回退之前页面占用的内存也不会释放。有时浏览十几个网页都会占用几百兆的内存。这样加载网页较多时会导致系统不堪重负最终强制关闭应用也就是出现应用闪退或重启public class MainActivity5 extends AppCompatActivity { private WebView mWebView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_web); mWebView (WebView) findViewById(R.id.web); mWebView.loadUrl(http://www.cnblogs.com/whoislcj/p/5720202.html); } }造成内存泄漏原因分析加载网页有缓存当加载了许多网页并且手机配置比较低时造成的内存泄漏就对手机影响很大查看报错结果如下解决办法Override protected void onDestroy() { if (mWebView ! null) { mWebView.loadDataWithBaseURL(null, , text/html, utf-8, null); mWebView.clearHistory(); ViewGroup parent (ViewGroup) mWebView.getParent(); if(parent!null){ parent.removeView(mWebView); } mWebView.destroy(); mWebView null; } super.onDestroy(); }5.6 资源未关闭造成的内存泄漏对于使用了BraodcastReceiverContentObserverFileCursorStreamBitmap等资源的使用应该在Activity销毁时及时关闭或者注销否则这些资源将不会被回收造成内存泄漏。5.7 未注销EventBus导致的内存泄漏Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); EventBus.getDefault().register(this); } Subscribe public void onEvent(MessageEvent msg) { }Override protected void onDestroy() { super.onDestroy(); //未移除注册的EventBus //EventBus.getDefault().unregister(this); }5.8 静态集合使用不当导致的内存泄漏添加Activity到栈或者移除Activity出栈。导致内存泄漏public class ActivityCollector { public static ListActivity activities new ArrayListActivity(); public static void addActivity(Activity activity) { activities.add(activity); } public static void removeActivity(Activity activity) { activities.remove(activity); } } Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_common); ActivityCollector.addActivity(this); } Override protected void onDestroy() { super.onDestroy(); //静态集合没有移除元素 //ActivityCollector.removeActivity(this); }5.9 使用弱引用避免内存泄漏在 Activity 中避免使用非静态内部类比如上面我们将 Handler 声明为静态的则其存活期跟 Activity 的生命周期就无关了。同时通过弱引用的方式引入 Activity避免直接将 Activity 作为 context 传进去public class WeakReferenceActivity extends AppCompatActivity { //将Handler声明为静态 没有了Activity的引用, 无法直接引用其变量或方法, //使用弱引用WeakReference来解决这个问题 private static class DBHandler extends Handler { //弱引用, 而不是使用外部类this或者传进来 private final WeakReferenceWeakReferenceActivity mActivity; public DBHandler(WeakReferenceActivity activity) { mActivity new WeakReference(activity); } Override public void handleMessage(Message msg) { WeakReferenceActivity activity mActivity.get(); if (activity ! null) { Toast.makeText(activity, what: msg.what, Toast.LENGTH_SHORT).show(); } } } private final DBHandler mHandler new DBHandler(this); private static final Runnable sRunnable new Runnable() { Override public void run() { Toast.makeText(App.getInstance(), sRunnable run(), Toast.LENGTH_SHORT).show(); } }; Override protected void onCreate(Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_weak_reference); mHandler.postDelayed(sRunnable, 1000 * 20); } public void onClick(View view) { mHandler.sendEmptyMessage(new Random().nextInt(10)); } }