首页 存档 技术 查看内容

Android 内存优化 为什么优化 如何检测 优化方案 参考

2018-3-30 13:00 |来自: 互联网 485 0

摘要: 为什么优化 虽然 Java 对内存的释放有垃圾自动回收机制,但是实际开发中,不再用到的对象因为被错误引用会导致无法回收,从而造成内存泄漏,甚至内存溢出 OOM(OutOfMemory),程序崩溃。 Android GC 原理 参考:And ...


为什么优化

虽然 Java 对内存的释放有垃圾自动回收机制,但是实际开发中,不再用到的对象因为被错误引用会导致无法回收,从而造成内存泄漏,甚至内存溢出 OOM(OutOfMemory),程序崩溃。

Android GC 原理

参考:Android GC 原理探究

Android 内存管理

参考:Android 内存管理

如何检测

使用 LeakCanary

Android 内存泄漏检测库:https://github.com/square/leakcanary ,善于使用 LeakCanary 发现内存泄漏。

Memory Monitor工具

Android Studio 中的 Android Monitor ,选择其中的 Memory,跟踪整个 APP 的内存变化情况
步骤如下:
1、与您的应用交互,在 Memory 监视器中,查看 Free 和 Alloated 内存。
2、点击 Dump Java Heap:,这个会打开 HPROF 查看器,如果没有,在 Captures 标签中,双击堆快照文件以打开 HPROF 查看器。
3、要引起堆分配,请与您的应用交互,然后点击触发 GC 的按钮:

Heap Viewer 工具

实时查看App分配的内存大小和空闲内存大小,发现 Memory Leaks
详细使用教程:Heap Viewer工具

Allocation Tracker

追踪内存对象的来源
详细使用教程:Allocation Tracker(Device Monitor)

优化方案

检查使用多少内存

每个 APP 的堆(heap)内存大小有硬性限制,如果您的 APP 已达到堆内存限制,并尝试分配更多的内存,系统会抛出 OutOfMemoryError 。为了避免 OOM ,您可以查询当前设备有多少堆空间,可以通过调用系统 getMemoryInfo() 查询,返回 一个ActivityManager.MemoryInfo 对象,它提供该设备当前存储器的状态信息,包括可用的存储器,总存储器,和低于该阈值存储器。

private void getMemoryInfo() {
  ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
  ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
  activityManager.getMemoryInfo(memoryInfo);
  LogUtil.d("totalMem="   memoryInfo.totalMem   ",availMem="   memoryInfo.availMem);
  if (!memoryInfo.lowMemory) {
    // 运行在低内存环境
  }
}

当界面不可见时释放内存

实现 ComponentCallbacks2 API 中 onTrimMemory()) ,当回调参数 level 为 TRIM_MEMORY_UI_HIDDEN ,是用户点击了Home键或者Back键退出应用,所有UI界面被隐藏,这时候应该释放一些不可见的时候非必须的资源。

public class MainActivity extends AppCompatActivity
  implements ComponentCallbacks2 {
  // Other activity code ...
  /**
   * Release memory when the UI becomes hidden or when system resources become low.
   * @param level the memory-related event that was raised.
   */
  public void onTrimMemory(int level) {
    // Determine which lifecycle or system event was raised.
    switch (level) {
      case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
        /*
          Release any UI objects that currently hold memory.
          The user interface has moved to the background.
        */
        break;
      case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
      case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
      case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
        /*
          Release any memory that your app doesn't need to run.
          The device is running low on memory while the app is running.
          The event raised indicates the severity of the memory-related event.
          If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
          begin killing background processes.
        */
        break;
      case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
      case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
      case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
        /*
          Release as much memory as the process can.
          The app is on the LRU list and the system is running low on memory.
          The event raised indicates where the app sits within the LRU list.
          If the event is TRIM_MEMORY_COMPLETE, the process will be one of
          the first to be terminated.
        */
        break;
      default:
        /*
         Release any non-critical data structures.
         The app received an unrecognized memory level value
         from the system. Treat this as a generic low-memory message.
        */
        break;
    }
  }
}

该 onTrimMemory() 回调是在搭载Android 4.0(API级别14)加入。对于早期版本,您可以使用 onLowMemory() 回调作为旧版本的回调,这大致相当于 TRIM_MEMORY_COMPLETE事件。

谨慎使用服务

离开了 APP 还在运行服务是最糟糕的内存管理错误之一,当 APP 处在后台,我们应该停止服务,除非它需要运行的任务。我们可以使用 JobScheduler 替代实现,JobScheduler 把一些不是特别紧急的任务放到更合适的时机批量处理。如果必须使用一个服务,最佳方法是使用 IntentService ,限制服务寿命,所有请求处理完成后,IntentService 会自动停止。

使用优化的数据容器

考虑使用优化过数据的容器 SparseArray / SparseBooleanArray / LongSparseArray 代替 HashMap 等传统数据结构,通用 HashMap 的实现可以说是相当低效的内存,因为它需要为每个映射一个单独的条目对象。

避免在 Android 上使用枚举

枚举往往需要两倍多的内存,静态常量更多,我们应该严格避免在 Android 上使用枚举。

使用 nano protobufs 序列化数据

Protocol buffers 是一个语言中立,平台中立的,可扩展的机制,由谷歌进行序列化结构化数据,类似于 XML 设计的,但是更小,更快,更简单。如果需要为您的数据序列化与协议化,建议使用 nano protobufs。

避免内存流失

内存流失可能会导致出现大量的 GC 事件,如自定义组件的 onDraw() ,避免大量创建临时对象,比如 String ,以免频繁触发 GC。GC 事件通常不影响您的 APP 的性能,然而在很短的时间段,发生许多垃圾收集事件可以快速地吃了您的帧时间,系统上时间的都花费在 GC ,就有很少时间做其他的东西像渲染或音频流。

使用ProGuard来剔除不需要的代码

使用 ProGuard 来剔除不需要的代码,移除任何冗余的,不必要的,或臃肿的组件,资源或库完善 APP 的内存消耗。

降低整体尺寸APK

您可以通过减少 APP 的整体规模显著减少 APP 的内存使用情况。文章: 声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除


路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部