《移动App性能评测与优化》读后感—内存篇

名词解释

  • VSS- Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
  • RSS- Resident Set Size 实际使用物理内存(包含共享库占用的内存)
  • PSS- Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
  • USS- Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS

Android 应用的内存组成

  1. Dalvik 虚拟机代码 -- 共享内存
  2. 应用框架代码 -- 共享内存
  3. 应用框架资源-- 共享内存
  4. 应用框架 so 库 -- 共享内存
  5. 应用的代码 -- 私有内存
  6. 应用的资源-- 私有内存
  7. 应用的 so 库 -- 私有内存
  8. 堆内存,其他部分 -- 共享/私有

内存组成索引

  • Native Heap: Native 代码分配的内存, 虚拟机和 Android 框架本身也会分配
  • Dalvik Heap: Java 代码分配的对象
  • Dalvik Other: 类的数据结构和索引
  • so mmap: Native 代码和常量
  • dex mmap: Java 代码和常量

Dalvik 内存组成

  • Dalvik-Heap 所有的 Java 实例
  • Dalvik-Other 存放类的数据结构及关系
    • LinearAlloc 载入类的函数信息, 随 dex 中函数数量的增加而增加(65535)
    • Code-Cache jit 编译代码后的缓存,随代码负责度的增大而增大
    • Accounting 用于标记和指针
    • dalvik-aux-structure 随类及方法数的增大而增大
    • dalvik-bitmap 随 dalvik-heap 的增大而增大

mmap

映射 classes.dex 文件。Dalvik 迅疾需要从 dex 文件中加载类信息、字符串常量等, 还需要在调用函数的时候直接从 mmap 内存中读取函数代码(dvm bytecode)执行; 所以该部分内存是程序运行必不可少的。
应用的 dex 会占据较大的空间, 并且随着代码增加, dex 文件变大, 占用的内存也会增加。

zygote 共享内存机制

Dalvik Pss = 私有内存(Private Dirty) + (共享内存 Shared Dirty / 共享进程数)

一个类的内存消耗

Foo f = new Foo();

一、 loadClass 操作,将类信息从 dex 文件加载进内存:

  1. 读取 .dex mmap 中 class 对应的数据
  2. 分配 native-heap 和 dalvik-heap 内存创建 class 对象
  3. 分配 dalvik-LinearAlloc 存放 class 数据
  4. 分配 dalvik-aux-structure 存放 class 数据

二、 new instance 操作, 创建对象实例:

  1. 执行 .dex mmap 中 代码
  2. 分配 dalvik-heap 创建 class 对象实例

在这个过程中,可能还会分配 dalvik-bitmap 和 jit-code-cache 内存。 如果 class Foo 引用了其他类, 继续按照同样的逻辑创建被引用的 class。

优化策略

Heap 优化

注意内存碎片

  • 尽量不要在循环中创建很多临时变量
  • 可以将大型的循环拆散、分段或按需执行

原因:内存分配的最小单位是页面, 通常为 4KB。

  1. 运行过程中生成很多临时变量
  2. 批量生成过程中, 由于还有空闲内存,虚拟机没有做垃圾回收
  3. 完成后进行垃圾回收, 清楚所有的临时变量,留下内存碎片。

因为 DVM 没有内存整理功能,可能一整页的内存被使用的只有很小一部分, 但是计算私有内存还是按照整页 4KB 计算。

Dalvik Other 优化

dex 文件中数据基本是按类名的字母顺序排列的, 这样同包名的类会排在一起。实际执行过程中, 同一个 package 下的类并不会全部同时被调用, 而是和很多其他的 package 下的类进行交互。 mmap 加载了整个页面, 其中可能很多是无用数据。可以通过混淆把互相调用的类改为同一个 package。

精简代码, 无用的代码随时清除。 并不是不运行就不会占用内存了。

你可能感兴趣的:(《移动App性能评测与优化》读后感—内存篇)