您当前的位置: 首页 > 
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

内存优化整理

沙漠一只雕得儿得儿 发布时间:2021-12-02 10:07:08 ,浏览量:0

  • 一、dumpsys meminfo 查询内存划分
  • 二、Java内存优化
    • 2.1 java内存泄漏优化
  • 三、Native内存优化
    • 3.1 malloc_debug模式
    • 3.1 使用 python 分析
  • 四、线程/fd泄漏分析
    • 4.1 fd简述
    • 4.2 常见原因
    • 4.3 查看fd
    • 4.4 查看线程树
    • 4.5 查看线程调用栈
  • 五、附(Python3环境工具)

一、dumpsys meminfo 查询内存划分

使用dumpsys meminfo  [packageName] 命令可以查询该进程下pss(Proportional Set Size 实际使用的物理内存)内存划分

重点字段解读:

  • Native Heap - Native 堆内存:调用 malloc/new (C/C++)占据的内存

  • Dalvik Heap - Dalvik虚拟机内存,Dalvik虚拟机代码在 libdvm.so 主要负责运行时dex解析成机器码

  • .art mmap - Android RunTime 映射内存,art 代码在 android_runtime.so, mmap(是linux C 的一个函数接口,用来做内存映射)

  • Private Dirty - 进程独占的内存,内存已经被本进程修改过,只能被自己进程使用

  • Private clean - 进程独占的内存,内存是映射过来的,没有做修改,可以置换给到其他进程使用

  • java heap - java堆内存 = Dalvik heap(dirty+ clean) + art heap (dirty + clean)

  • Total - 整个应用占据的总内存
  • Graphics - 用于图形缓冲区队列的内存,用于在屏幕上显示像素,包括GL表面,GL纹理等(如果没有用到 OpenGL 或者不是游戏,可以直接忽略)

  • Stack - 线程栈占据的内存

  • Code - 应用程序使用代码和资源的内存,如dex字节码,优化或编译的dex代码,.so库和字体 

二、Java内存优化 2.1 java内存泄漏优化

java内存泄漏的主要是由于java对象被单例、匿名内部类、监听类等持有而无法释放导致的,具体的排查和解决方法可以参考:

内存泄漏优化整理

三、Native内存优化

android中Native内存泄漏的原因较为复杂,可能是添加ImageView过多或者开启硬件加速导致Bitmap像素内存增长,或是某个播放库申请内存较多,故需要多个方面去定位分析。

3.1 malloc_debug模式

malloc_debug是谷歌推荐的一种定位Native内存泄露方法,需要root权限 。以下为各个android版本开启malloc_debug的方式:

1)如果是Android 8.x,执行以下命令(N为调用栈层级数,推荐为2)

1

2

3

//查询所有内存

adb shell setprop wrap. '"LIBC_DEBUG_MALLOC_OPTIONS=backtrace=N  logwrapper"'

adb shell am force-stop

2)如果是Android 7.x (8.x 也可以用),执行以下命令,其中app_process照写,不需要针对调试的app更改

1

2

3

4

5

adb root

adb shell stop

adb shell setprop lib.debug.malloc.program app_process

adb shell setprop lib.debug.malloc.options "\"backtrace leak_track\""

adb shell start

3)如果是Android 5.x / 6.x,执行以下命令

1

2

3

4

adb root

adb shell setprop libc.debug.malloc=1

adb shell stop

adb shell start

执行命令后,在应用操作复现路径或者monkey一段时间后,使用以下命令dump出native内存

1

adb shell am dumpheap -n /data/local/tmp/native.txt

3.1 使用 python 分析

使用开源的Python工具native_heapdump_viewer.py分析native内存

1)环境配置:

python2运行环境

arm-linux-androideabi-objdump环境变量配置

arm-linux-androideabi-addr2line环境变量配置

存放带有符号信息so文件的文件夹(/path/to/symbols/)

2)运行命令:

1

python native_heapdump_viewer.py --html --symbols  /path/to/symbols/  native.txt > heap_info.html

3)malloc_debug 内存文件分析:

查看生成的heap_info.html

字段解读:

BYTES- 占用的内存大小单位byte %TOTAL - 占总 native 内存百分比 %PARENT - 占父帧内存百分比 COUNT - 调用了多少次 ADDR- 内存地址 LIBRARY - 占用的内存所属哪一个 so 库 FUNCTION- 占用的内存所属哪一个方法 LOCATION - 占用的内存所属哪一行

可以看出Native总内存约329M,其中libhwui.so库申请bitmap像素内存100M,占比30%;libHCDNClientNet.so库申请内存67M,占比20%;libgnustl_shared.so库申请内存43M,占比13%。

此处申请bitmap像素内存和播放库内存占比较高,需要再结合实际情况跟进分析。

四、线程/fd泄漏分析 4.1 fd简述

Fd的全称是File descriptor,在Linux OS里,所有都可以抽象成文件,比如普通的文件、目录、块设备、字符设备、socket、管道等等。当通过一些系统调用(如open/socket等),会返回一个fd(一个数字),然后根据这个fd对应的文件进行操作,比如读、写。在内核进程结构体task_struct中为每个进程维护了一个数组,数组下标就是fd,里面存储的是对这个文件的描述。

Linux默认每个进程能打开的fd数最大值是1024,当应用进程打开的文件数超过这个限制值后就无法再打开文件了,系统会报相关的错误,Too many open files是Linux系统中程序打开的文件数过多的常见错误。

4.2 常见原因

1)HandlerThread 若频繁地创建HandlerThread对象,内部的Looper创建会导致fd超限。 2)Thread.start() 调用Thread.start()启动线程后,在native层调用open方法创建ashmem rigions,这会产生fd,如果循环地创建启动过多的线程就会产生fd泄露。 3)Resource相关 使用输入输出流没有关闭可能会出问题,FileInputStream、FileOutputStream、FileReader、FileWriter 等每打开一个文件需要fd,一些输入流也提供了基于fd的构造方法。文件流在finally块中调close方法,或者使用Java 7 编译器和运行环境支持的 try-with-resources 语句可以避免fd泄露。 4)InputChannel 对于system server,,如果有大量的socket 打开,可能是因为Input Channel没有关闭,抓取hprof查看system server中WindowState的情况进行分析。 5)Bitmap 创建Bitmap在native层会产生fd,如果使用完后不关闭,可能引发fd的泄露。

4.3 查看fd

1

2

3

4

//查看每个fd

ls -a -l /proc//fd

//查看fd总数

ls -a -l /proc//fd | wc -l

4.4 查看线程树

1

pstree

4.5 查看线程调用栈

1

2

3

4

//java线程可以用DDMS工具或者jstack查看调用栈

jstack [-l]

//native线程可以用pstack工具(依赖gdb)查看调用栈

sh pstack.sh

正在上传…重新上传取消​gdb正在上传…重新上传取消​pstack.sh

五、附(Python3环境工具)

正在上传…重新上传取消​native_heapdump_viewer.py

关注
打赏
1657159701
查看更多评论
立即登录/注册

微信扫码登录

0.0391s