内存优化一

调查 RAM 使用情况

开发 Android 应用时,请始终注意您的应用使用了多少随机存取存储器 (RAM)。尽管 Dalvik 和 ART 运行时会执行例行垃圾回收 (GC),您仍然需要了解应用何时以及在哪里分配和释放内存。为了提供稳定的用户体验,使 Android 操作系统能够在应用之间快速切换,请确保您的应用在用户不与其交互时不会消耗不必要的内存。

即使您在开发过程中遵循了管理应用的内存的所有最佳做法,您仍然可能泄漏对象或引入其他内存错误。唯一能够确定您的应用尽可能少地使用内存的方法是,利用本文介绍的工具分析应用的内存使用情况。

解读日志消息

开始调查您的应用内存使用情况的最简单切入点是运行时日志消息。有时,发生垃圾回收时,您可以在 logcat 中查看消息。

Dalvik 日志消息

在 Dalvik(而不是 ART)中,每次垃圾回收都会将以下信息打印到 logcat 中:

D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>

示例:
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
  • 垃圾回收原因<GC_Reason>GC_CONCURRENT
    什么触发了垃圾回收以及是哪种回收。可能出现的原因包括:

    • GC_CONCURRENT
      在您的堆开始占用内存时可以释放内存的并发垃圾回收。
    • GC_FOR_MALLOC
      堆已满而系统不得不停止您的应用并回收内存时,您的应用尝试分配内存而引起的垃圾回收。
    • GC_HPROF_DUMP_HEAP
      当您请求创建 HPROF 文件来分析堆时出现的垃圾回收。
    • GC_EXPLICIT
      显式垃圾回收,例如当您调用 gc() 时(您应避免调用,而应信任垃圾回收会根据需要运行)。
    • GC_EXTERNAL_ALLOC
      这仅适用于 API 级别 10 及更低级别(更新版本会在 Dalvik 堆中分配任何内存)。外部分配内存的垃圾回收(例如存储在原生内存或 NIO 字节缓冲区中的像素数据)。
  • 释放量<Amount_freed>freed 2049K
    从此次垃圾回收中回收的内存量。

  • 堆统计数据<Heap_stats>65% free 3571K/9991K
    堆的可用空间百分比与(活动对象数量)/(堆总大小)。

  • 外部内存统计数据<External_memory_stats>external 4703K/5261K
    API 级别 10 及更低级别的外部分配内存(已分配内存量)/(发生回收的限值)。

  • 暂停时间<Pause_time>paused 2ms+2ms
    堆越大,暂停时间越长。并发暂停时间显示了两个暂停:一个出现在回收开始时,另一个出现在回收快要完成时。
    在这些日志消息积聚时,请注意堆统计数据的增大(上面示例中的 3571K/9991K 值)。如果此值继续增大,可能会出现内存泄漏。

ART 日志消息

与 Dalvik 不同,ART 不会为未明确请求的垃圾回收记录消息。只有在认为垃圾回收速度较慢时才会打印垃圾回收。更确切地说,仅在垃圾回收暂停时间超过 5ms 或垃圾回收持续时间超过 100ms 时。如果应用未处于可察觉的暂停进程状态,那么其垃圾回收不会被视为较慢。始终会记录显式垃圾回收。

ART 会在其垃圾回收日志消息中包含以下信息:

I/art: <GC_Reason> <GC_Name> <Objects_freed>(<Size_freed>) AllocSpace Objects, <Large_objects_freed>(<Large_object_size_freed>) <Heap_stats> LOS objects, <Pause_time(s)>
示例:
I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms
  • 垃圾回收原因<GC_Reason>Explicit
    什么触发了垃圾回收以及是哪种回收。可能出现的原因包括:
    • Concurrent
      不会暂停应用线程的并发垃圾回收。此垃圾回收在后台线程中运行,而且不会阻止分配。
    • Alloc
      您的应用在堆已满时尝试分配内存引起的垃圾回收。在这种情况下,分配线程中发生了垃圾回收。
    • Explicit
      由应用明确请求的垃圾回收,例如,通过调用 gc() 或 gc()。与 Dalvik 相同,在 ART 中,最佳做法是您应信任垃圾回收并避免请求显式垃圾回收(如果可能)。不建议使用显式垃圾回收,因为它们会阻止分配线程并不必要地浪费 CPU 周期。如果显式垃圾回收导致其他线程被抢占,那么它们也可能会导致卡顿(应用中出现间断、抖动或暂停)。
    • NativeAlloc
      原生分配(如位图或 RenderScript 分配对象)导致出现原生内存压力,进而引起的回收。
    • CollectorTransition
      由堆转换引起的回收;此回收由运行时切换垃圾回收引起。回收器转换包括将所有对象从空闲列表空间复制到碰撞指针空间(反之亦然)。当前,回收器转换仅在以下情况下出现:在 RAM 较小的设备上,应用将进程状态从可察觉的暂停状态变更为可察觉的非暂停状态(反之亦然)。
    • HomogeneousSpaceCompact
      齐性空间压缩是空闲列表空间到空闲列表空间压缩,通常在应用进入到可察觉的暂停进程状态时发生。这样做的主要原因是减少 RAM 使用量并对堆进行碎片整理。
    • DisableMovingGc
      这不是真正的垃圾回收原因,但请注意,发生并发堆压缩时,由于使用了 GetPrimitiveArrayCritical,回收遭到阻止。一般情况下,强烈建议不要使用 GetPrimitiveArrayCritical,因为它在移动回收器方面具有限制。
    • HeapTrim
      这不是垃圾回收原因,但请注意,堆修剪完成之前回收会一直受到阻止。
  • 垃圾回收名称<GC_Name>concurrent mark sweep
    ART 具有可以运行的多种不同的垃圾回收。
    • Concurrent mark sweep (CMS)
      整个堆回收器,会释放和回收映像空间以外的所有其他空间。
    • Concurrent partial mark sweep
      几乎整个堆回收器,会回收除了映像空间和 zygote 空间以外的所有其他空间。
    • Concurrent sticky mark sweep
      生成回收器,只能释放自上次垃圾回收以来分配的对象。此垃圾回收比完整或部分标记清除运行得更频繁,因为它更快速且暂停时间更短。</
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值