你的Android应用程序可以阻止泄漏内存的八种方式
来源:互联网 发布:红警2共和国之辉mac版 编辑:程序博客网 时间:2024/05/20 18:19
静态活动
这种泄漏
private static MainActivity activity; void setStaticActivity() { activity = this; }
被构造以揭示在静态类变量中持有对您的活动的引用的结果,该静态类变量将超过活动的任何特定实例。活动的类对象是app-global并且将保持在无限期的内存中的活动。有合理的理由,开发人员可能选择这样做,因此我们需要提出一个解决方案,不会阻止活动被垃圾收集一旦它准备好被销毁。Android提供了一组特殊的对象https://developer.android.com/reference/java/lang/ref/package-summary.html#classes,允许开发人员控制引用的“强度”。该活动正在泄漏,因为它继续被强烈引用,即使在意图是破坏它并释放它从内存。只要此引用存在,垃圾回收器就无法清除活动的内存。因此,我们可以使用WeakReferencehttps://developer.android.com/reference/java/lang/ref/WeakReference.html解决泄漏。弱引用不会阻止对象的内存被回收,因此如果只有对对象的弱引用仍然存在,它将有资格进行垃圾回收。
private static WeakReference<MainActivity> activityReference; void setStaticActivity() { activityReference = new WeakReference<MainActivity>(this); }
静态视图
静态维护对视图的引用
private static View view; void setStaticView() { view = findViewById(R.id.sv_button); }
从一个活动是一样有问题的直接引用活动本身,因为视图包含对它们所在的活动的引用。因此,一个WeakReference在解决这个泄漏同样有效。但是,当我们清楚Activity对象处于它的生命周期结束时,我们也可以手动清除引用,并希望与垃圾回收器会面。为此,我们简单地覆盖Activity的onDestroy()方法,该方法保证在生命周期结束时调用,并将引用设置为null。
private static View view; @Override public void onDestroy() { super.onDestroy(); if (view != null) { unsetStaticView(); } } void unsetStaticView() { view = null; }
3.内在类
泄漏
private static Object inner; void createInnerClass() { class InnerClass { } inner = new InnerClass(); }
我们创建的是非常类似于上面两个。开发人员经常警告避免非静态嵌套类,称为内部类https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html,因为它们对外部类有隐含的引用,因此这是很容易无意中泄漏你的活动。然而,使用内部类是有好处的,例如能够访问外部类的私有成员,只要我们知道引用的生命周期,我们就可以防止泄漏。再一次,我们天真地创建了一个静态引用,这次是我们内部类的一个实例。为了解决泄漏,我们可以很容易地避免声明引用为静态,并像往常一样继续业务。
private Object inner; void createInnerClass() { class InnerClass { } inner = new InnerClass(); }
4-7。匿名类
到目前为止,我们看到的每个内存泄漏的根本原因是一个应用程序全局静态引用,直接或间接通过其他引用的链保存到Activity对象,并防止它被垃圾回收。我们使用AsyncTask创建的泄漏:
void startAsyncTask() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { while(true); } }.execute(); }
处理程序:
void createHandler() { new Handler() { @Override public void handleMessage(Message message) { super.handleMessage(message); } }.postDelayed(new Runnable() { @Override public void run() { while(true); } }, Long.MAX_VALUE >> 1); }
主题:
void spawnThread() { new Thread() { @Override public void run() { while(true); } }.start(); }
和TimerTask:
void scheduleTimer() { new Timer().schedule(new TimerTask() { @Override public void run() { while(true); } }, Long.MAX_VALUE >> 1); }
都是由声明一个匿名类https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html引起的。一个匿名类实际上只是一个专门的内部类,其主要优点是允许代码被简洁地编写。每当特定任务只需要一个特定类的一次性子类化时,Java提供了语法糖,它允许子类被声明为具有最小语法的表达式。这是伟大的写干净的代码,但可以导致一个新的,但密切相关的内存泄漏集。正如我们在上面看到的内部类,它们的实例是完全无害的,只要你不创建一个引用它们的活动的生命周期,它们被声明。但是,这些特定的匿名类都被用于产生应用程序的后台线程。这些java线程是app-global,并且维护对创建它们的对象的引用,匿名类实例,它反过来持有对外部类的引用,因为它是一个非静态内部类。线程可以永久运行,因此将持久性的内存链保存到垃圾收集器不执行其工作,即使在活动的生命周期完成后。这一次我们不能避免声明引用为静态,因为线程是全局的应用程序的状态。相反,为了避免Activity泄漏,我们必须放弃匿名类的简洁性,并将每个子类声明为静态嵌套类。一旦嵌套类是静态的,它不再维护对外部类实例的引用,并打破了我们的引用链。没有什么本质上区分这些特定的类,我们可以应用相同的技术AsyncTask:
private static class NimbleTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { while(true); } } void startAsyncTask() { new NimbleTask().execute(); }
处理程序:
private static class NimbleHandler extends Handler { @Override public void handleMessage(Message message) { super.handleMessage(message); } } private static class NimbleRunnable implements Runnable { @Override public void run() { while(true); } } void createHandler() { new NimbleHandler().postDelayed(new NimbleRunnable(), Long.MAX_VALUE >> 1); }
和TimerTask:
private static class NimbleTimerTask extends TimerTask { @Override public void run() { while(true); } } void scheduleTimer() { new Timer().schedule(new NimbleTimerTask(), Long.MAX_VALUE >> 1); }
但是,如果你坚持使用一个匿名类,你总是可以选择终止保持对象活动时间比活动更长的java线程。以下是为匿名地声明的Thread完成此操作的许多方法之一。由于我们希望线程与Activity一起结束,我们所要做的就是设计运行循环,以依赖线程的中断标志,然后在Activity的onDestroy()方法中设置标志。
private Thread thread; @Override public void onDestroy() { super.onDestroy(); if (thread != null) { thread.interrupt(); } } void spawnThread() { thread = new Thread() { @Override public void run() { while (!isInterrupted()) { } } } thread.start(); }
8.传感器管理器
这个例子
void registerListener() { SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL); sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST); }
只是使用Android系统服务可能泄露您的活动的许多方法之一。为了方便系统服务和Activity之间的通信,我们将Activity注册为侦听器,因此在服务的传感器管理器事件队列和我们的Activity之间创建一个引用链。只要我们的活动仍然在传感器管理器注册,引用将不会被释放,泄漏将持续。一旦活动在其生命周期结束,真的没有任何理由,它应该继续从任何传感器侦听事件。为了解决泄漏,我们所需要做的就是在活动结束时注销监听器。
private SensorManager sensorManager; private Sensor sensor; @Override public void onDestroy() { super.onDestroy(); if (sensor != null) { unregisterListener(); } } void unregisterListener() { sensorManager.unregisterListener(this, sensor); }
活动泄漏都是植根于我们在这里看到的和那些非常相似的特殊情况。现在,我们已经建议如何解决这些具体问题,您可以应用相同的技术,以任何未来的泄漏可能会出现。内存泄漏一旦被识别就很容易压缩,只要你经常检查它们,你可以早点赶上它们,为用户创造最好的体验。
- 你的Android应用程序可以阻止泄漏内存的八种方式
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- Android内存泄漏的八种可能
- 再谈android内存泄漏—常见的八种导致 APP 内存泄漏的问题
- [译]Android内存泄漏的八种可能
- [译]Android内存泄漏的八种可能
- [译]Android内存泄漏的八种可能(上)
- Android内存泄漏的八种可能(上)
- Android防止内存泄漏的八种方法(下)
- Android防止内存泄漏的八种方法
- java反射机制
- 通话距离感应实现源码
- 【大数据新手上路】“零基础”系列课程--Flume收集网站日志数据到MaxCompute
- sql server存储过程的笔记记录
- ReentrantLock 和 Synchronized对比
- 你的Android应用程序可以阻止泄漏内存的八种方式
- iOS开发
- 瑞利分布
- 判断用户名是否正确
- 浅谈设置父元素透明度不影响子元素透明度
- Linux中目录文件的权限及其对应的操作
- Btree索引详解
- struts2,springmvc RequestPayload数据获取的方式
- hibernate学习1