HaaS100开发调试系列 之 定位AliOS Things内存及Crash问题

简介: 本文主要说开发调试过程中经常遇到的内存问题。

这是《HaaS100开发调试系列》第5篇,建议读者把前面几篇快速浏览一下,可以帮助大家尽快上手AliOS Things的开发调试。链接是:

一文轻松入门HaaS100诊断调试系统

HaaS100开发调试系列 之 如何使用J-Link仿真器调试代码

HaaS100 开发调试系列 之 CPU利用率(cpuusage)的原理与使用

HaaS100开发调试系列 之 使用AliOS Things诊断调试组件定位Bug

本文主要说开发调试过程中经常遇到的内存问题。

1、先抛出问题

在开发过程中,我们总是会遇到诸如:

  • 系统总内存怎么查询?
  • 系统剩余可用内存还有多少呢,我的应用需要malloc 100KB空间,能成功吗?
  • 查询到的系统可用内存还有200KB,为什么我连50KB都申请不到了呢?
  • 系统跑着跑着,就会产生异常crash而死机了,查到原因是系统动态内存耗尽了,即出现了典型的内存泄漏,这个时候应该从哪着手查起呢?

上述的内存问题总是让人头痛,因此AliOS Things给大家提供了一套强大的内存问题分析定位方法,即:

  • 内存查询专用的CLI命令
  • 内存查询API接口
  • 内存log解析工具
  • 内存dump机制
  • 内存解析工具

结合这四种方法,我们希望尽可能给开发者提供系统内存分析,帮助开发者进一步定位内存问题。

2、打开相关组件

内存问题分析,依赖AliOS Things提供的cli组件和debug组件。打开步骤如下:

step1

在package.yaml 文件里添加 cli组件和debug组件。

举例说明,我们当前使用的是helloworld_demo,那我们进入solution/helloworld_demo/package.yaml,增加:

depends:
 
- cli: rel_3.3.0    # helloworld_demo中添加cli组件
 
- debug: rel_3.3.0  # helloworld_demo中添加debug组件

Step2

使能内存调试宏RHINO_CONFIG_MM_DEBUG,方法是在 solution/helloworld_demo/package.yaml里增加

def_config:                              # 组件的可配置项
 
    RHINO_CONFIG_MM_DEBUG: 1

Step3

重新编译烧录板子,参考 HaaS100快速开始

Step4

上电后系统启动后,执行help看一下,系统自带了一些调试命令。

image.png

3、内存CLI命令

3.1、内存状态查询

执行dumpsys mm 查看系统内存状态,会有下面的打印输出(举例):

dumpsys mm

image.png

字段解释

HEAP中的内容含义(单位为字节):

  • TotalSz:系统可供malloc的动态内存总大小;
  • FreeSz:系统当前空闲内存大小;
  • UsedSz:系统当前已经分配的内存大小,即UsedSz = TotalSz – FreeSz;
  • MinFreeSz:系统空闲内存的历史最小值,即TotalSz – MinFreeSz 便是内存历史使用量峰值;
  • MaxFreeBlkSz:系统最大空闲块Size,表示系统此时可供分配出来的内存最大值。

上面各字段就可以回答本文开头的一些问题:

“系统总内存怎么查询”—— TotalSz

“系统剩余可用内存”—— FreeSz

“查询到的系统可用内存还有200KB,为什么我连50KB都申请不到了呢?” —— 查看MaxFreeBlkSz,这个字段表示系统此时可供分配出来的内存最大值。如果系统存在大量小内存(如size低于256字节的内存)不断malloc和free的情况,系统会产生一些内存碎片,这个时候即使系统可用内存(FreeSz)还够,也只能最大分配出MaxFreeBlkSz的内存。关于AliOS Things使用的内存算法和对内存碎片的处理,请读者关注我们后续的文章。

3.2、内存log dump

执行dumpsys mm_info 可将系统的详细动态内存信息dump出来,如果系统有很多的内存malloc,这一步可能会dump的时间比较久,示例如下:

dumpsys mm_info
------------------------------- all memory blocks ---------------------------------
 
g_kmm_head = 34002240
 
ALL BLOCKS
 
address,  stat   size     dye     caller   pre-stat    point
 
0x34002318  used       8  fefefefe  0x0        pre-used;
 
0x34002330  used      32  fefefefe  0x229ad7   pre-used;
 
0x34002360  used      32  fefefefe  0x22b5cf   pre-used;
 
0x34002390  used      40  fefefefe  0x22d14f   pre-used;
 
0x340023c8  used      32  fefefefe  0x208e03   pre-used;
 
0x340023f8  used      40  fefefefe  0x22c3af   pre-used;
 
0x34002430  used      40  fefefefe  0x22c3af   pre-used;
 
0x34002468  used      40  fefefefe  0x22d14f   pre-used;
 
0x340024a0  used      32  fefefefe  0x229ad7   pre-used;
 
0x340024d0  used      32  fefefefe  0x22b5cf   pre-used;
 
0x34002500  used      80  fefefefe  0x207b67   pre-used;
 
0x34002560  used      32  fefefefe  0x229ad7   pre-used;
 
0x34002590  used      32  fefefefe  0x22b5cf   pre-used;
 
0x340025c0  used      40  fefefefe  0x22d14f   pre-used;
 
0x340025f8  used      32  fefefefe  0x229ad7   pre-used;
 
0x34002628  used      32  fefefefe  0x22b5cf   pre-used;
 
0x34002658  used  131072  fefefefe  0x22d865   pre-used;
 
0x34022668  used     200  fefefefe  0x22d86f   pre-used;
 
0x34022740  used    2048  fefefefe  0x1c5d8979 pre-used;
 
0x34022f50  used      40  fefefefe  0x1c5ddc59 pre-used;
 
0x34022f88  used     800  fefefefe  0x1c5d671b pre-used;
 
0x340232b8  used    8192  fefefefe  0x22d865   pre-used;
 
0x340252c8  used     200  fefefefe  0x22d86f   pre-used;
 
0x340253a0  used      32  fefefefe  0x1c5d9055 pre-used;
 
0x340253d0  used      40  fefefefe  0x1c5d5cf9 pre-used;
 
0x34025408  used    5120  fefefefe  0x1c5dd8fd pre-used;
 
0x34026818  used      80  fefefefe  0x1c5d5da7 pre-used;
 
0x34026878  used    3072  fefefefe  0x22d865   pre-used;
 
0x34027488  used     200  fefefefe  0x22d86f   pre-used;
 
0x34027560  used      40  fefefefe  0x1c5d7901 pre-used;
 
0x34027598  used      40  fefefefe  0x1c5d7935 pre-used;
 
0x340275d0  used      40  fefefefe  0x22c3af   pre-used;
 
0x34027608  used      32  fefefefe  0x1c5dde4f pre-used;
 
0x34027638  used      32  fefefefe  0x1c5d90e7 pre-used;
 
0x34027668  used      40  fefefefe  0x1c5d8e03 pre-used;
 
0x340276a0  used      40  fefefefe  0x1c5d5cf9 pre-used;
 
0x340276d8  used      32  fefefefe  0x1c5d9161 pre-used;
 
0x34027708  used      32  fefefefe  0x1c5d916b pre-used;
 
0x34027738  used     432  fefefefe  0x2078a7   pre-used;
 
0x340278f8  used    1024  fefefefe  0x207dc7   pre-used;
 
0x34027d08  used     512  fefefefe  0x1c5d6251 pre-used;
 
0x34027f18  free  6660872  abababab  0x0        pre-used; free[(nil)   ,(nil)   ]
 
0x34682230  used  sentinel  fefefefe  0x0        pre-free [0x34027f18];
 
 
 
----------------------------- all free memory blocks -------------------------------
 
freelist bitmap: 0x20000
 
address,  stat   size     dye     caller   pre-stat    point
 
0x34027f18  free  6660872  abababab  0x0        pre-used; free[(nil)   ,(nil)   ]
 
 
 
------------------------- memory allocation statistic ------------------------------
 
---------------------------------------------------------------------------
 
[HEAP]| TotalSz    | FreeSz     | UsedSz     | MinFreeSz  | MaxFreeBlkSz  |
 
      | 0x00680000 | 0x0065A308 | 0x00025CF8 | 0x0065A0F8 | 0x0065A308    |
 
---------------------------------------------------------------------------
 
 
 
-----------------number of alloc times:-----------------
 
[2^06] bytes:    33   |[2^07] bytes:     1   |[2^08] bytes:     3   |[2^09] bytes:     1   |
 
[2^10] bytes:   987   |[2^11] bytes:     1   |[2^12] bytes:     2   |[2^13] bytes:     1   |
 
[2^14] bytes:     1   |[2^15] bytes:     0   |[2^16] bytes:     0   |[2^17] bytes:     0   |
 
[2^18] bytes:     1   |[2^19] bytes:     0   |[2^20] bytes:     0   |[2^21] bytes:     0   |
 
[2^22] bytes:     0   |[2^23] bytes:     0   |[2^24] bytes:     0   |[2^25] bytes:     0   |
 
[2^26] bytes:     0   |[2^27] bytes:     0   |[2^28] bytes:     0   |[2^29] bytes:     0   |

字段解释

重点关注的是“ all memory blocks”下面的log,其中几个关键的字段含义为:

  • address:用户malloc后,系统分配出来的地址,即malloc的返回值
  • stat: 内存状态,used表示malloc后内存还在使用,free表示这块内存已经释放
  • size:malloc的大小(单位:字节)
  • caller:调用malloc的地方,即这块内存的使用者是谁。
  • dye/pre-stat:AliOS Things使用的内存管理算法相关,这里不赘述。

4、查看内存的API接口

如果需要在代码中调用内存状态查询,AliOS Things也提供了如下API接口,该接口的输出与上述执行dumpsys mm的输出一致。

//需要包含的头文件

#include "aos/debug.h"

//接口调用方法

aos_debug_mm_overview(NULL)

5、内存log解析工具的使用

面对上面dumpsys mm_info命令输出的这么多log,我们怎么分析呢?

配合解析脚本 coredump_parser.py, 我们可以得到下面的结果:

========== Show MM Statistic Info  ==========
 
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 
 Alloc Addr  |           Func           | Cnt  |  Total Size  |   Line   |       File     
 
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 
  0x208e03   |          srand           |  1   |      32      |          |     reent.c    
 
 0x1c5d9055  | aos_register_event_filter |  1   |      32      |   131    | /workspace/hass/AliOS-Things/components/utility/yloop/src/local_event.c
 
 0x1c5dde4f  |    vfs_inode_set_name    |  1   |      32      |    25    | /workspace/hass/AliOS-Things/core/vfs/vfs_inode.c
 
 0x1c5d90e7  |      aos_loop_init       |  1   |      32      |    85    | /workspace/hass/AliOS-Things/components/utility/yloop/src/yloop.c
 
 0x1c5d9161  |     aos_poll_read_fd     |  1   |      32      |   113    | /workspace/hass/AliOS-Things/components/utility/yloop/src/yloop.c
 
 0x1c5d916b  |     aos_poll_read_fd     |  1   |      32      |   114    | /workspace/hass/AliOS-Things/components/utility/yloop/src/yloop.c
 
 0x1c5ddc59  |     vfs_lock_create      |  1   |      40      |    17    | /workspace/hass/AliOS-Things/core/vfs/vfs_adapt.c
 
 0x1c5d7901  |      kv_lock_create      |  1   |      40      |    33    | /workspace/hass/AliOS-Things/core/kv/kv_adapt.c
 
 0x1c5d7935  |      kv_sem_create       |  1   |      40      |    82    | /workspace/hass/AliOS-Things/core/kv/kv_adapt.c
 
 0x1c5d8e03  |        event_open        |  1   |      40      |    40    | /workspace/hass/AliOS-Things/components/utility/yloop/src/device.c
 
  0x207b67   |        localtime         |  1   |      80      |          |     reent.c     
 
 0x1c5d5cf9  |      aos_mutex_new       |  2   |      80      |   147    | /workspace/hass/AliOS-Things/core/osal/aos/rhino.c
 
 0x1c5d5da7  |      aos_queue_new       |  1   |      80      |   349    | /workspace/hass/AliOS-Things/core/osal/aos/rhino.c
 
  0x22d14f   |  krhino_sem_dyn_create   |  3   |     120      |   102    | /workspace/hass/AliOS-Things/core/rhino/k_sem.c
 
  0x22c3af   | krhino_mutex_dyn_create  |  3   |     120      |   125    | /workspace/hass/AliOS-Things/core/rhino/k_mutex.c
 
  0x229ad7   |      osThreadCreate      |  4   |     128      |   250    | /home/william.wgj/work/code/shenmu_lite/shenmu_github/shenmu_aos/platform/mcu/haas1000
 
                                                                           /drivers/out/haas1000_normalization/../../rtos/rhino/cmsis/cmsis_os.c
 
  0x22b5cf   | krhino_event_dyn_create  |  4   |     128      |   102    | /workspace/hass/AliOS-Things/core/rhino/k_event.c
 
  0x2078a7   |       __sfmoreglue       |  1   |     432      |          |     reent.c     
 
 0x1c5d6251  |       proc_onecmd        |  1   |     512      |   156    | /workspace/hass/AliOS-Things/core/cli/cli.c
 
  0x22d86f   |     task_dyn_create      |  3   |     600      |   280    | /workspace/hass/AliOS-Things/core/rhino/k_task.c
 
 0x1c5d671b  |         cli_init         |  1   |     800      |   697    | /workspace/hass/AliOS-Things/core/cli/cli.c
 
  0x207dc7   |       __smakebuf_r       |  1   |     1024     |          |     reent.c    
 
 0x1c5d8979  |      hal_uart_init       |  1   |     2048     |   333    | /workspace/hass/AliOS-Things/platform/mcu/haas1000/hal/uart.c
 
 0x1c5dd8fd  |     uring_fifo_init      |  1   |     5120     |    25    | /workspace/hass/AliOS-Things/components/dm/ulog/ulog_ring_fifo.c
 
  0x22d865   |     task_dyn_create      |  3   |    142336    |   275    | /workspace/hass/AliOS-Things/core/rhino/k_task.c
 
--------------------------------------------------------------------------------------------------------------------------------------------------------------

使用方法

  1. 将串口输出的异常log 拷贝至coredump_parser.py的同级目录中,文件名任意,这里取名为log,coredump_parser.py路径为:https://github.com/alibaba/AliOS-Things/tree/dev_3.1.0_haas/components/utility/debug_tools
  2. 将编译生成的elf文件(aos.elf)也拷贝至coredump_parser.py的同级目录,elf 路径为solutions/helloworld_demo/out/helloworld_demo/aos.elf
  3. 执行下面命令(举例)
python coredump_parser.py log aos.elf

如果系统提示如“arm-none-eabi-gcc”找不到,表示使用的工具链没有在系统PATH下,

arm-none-eabi-gcc在 AliOS Things代码下载时自带的工具链toolchian里,toolchian路径为:

~/.aliot/arm-none-eabi/main/bin

可以将这个路径添加到系统PATH路径下,也可以使用-p参数,如

python coredump_parser.py log aos.elf -p  ~/.aliot/arm-none-eabi/main/bin

这个工具会将系统内存malloc情况输出到表格中,并且按照Total Size从小到大排序,同时指出了每个内存块的申请者caller在代码中的位置,一目了然。如果开发者定位或者怀疑此时系统内出现了内存泄漏,那么经过上面的解析出的系统内存使用,我们可以直接看出哪个模块的内存只有申请没有释放了,一般是Total Size 最大的那个点!

6、小结

系统内存问题的定位比较复杂,使用上面几个方法,可以有效的帮助开发者定位排查一些内存问题,希望大家多多尝试上面的命令,灵活使用,才能发挥出AliOS Things的诊断调试的强大功能。

开发者支持
HaaS解决方案中心:https://haas.iot.aliyun.com/
HaaS技术社区:https://blog.csdn.net/HaaSTech

开发者钉钉群和公众号见下图,开发者钉钉群每天都有技术支持同学值班。

image.png

相关文章
|
安全 架构师 编译器
鲲鹏开发重点-–扭转x86乾坤的挑战,ARM64内存模型
因为X86及其CISC架构生态的封闭性,中国市场对未来处理器的选择,将是更开放、更模块化的RISC架构。 鲲鹏处理器就是符合这个潮流的创新产品和生态,将直面一系列挑战,和Apple一样赢得这场挑战,来扭转X86的封闭性的乾坤,创造出中国的处理器新生态。
762 0
鲲鹏开发重点-–扭转x86乾坤的挑战,ARM64内存模型
|
28天前
|
缓存 Java Android开发
安卓应用开发中的内存优化策略
在移动应用开发领域,性能一直是衡量应用质量的重要指标之一。特别是对于安卓平台,由于设备的硬件配置多样化,内存管理成为开发者面临的重大挑战。本文将深入探讨针对安卓平台的内存优化技巧,包括内存泄漏的预防、合理使用数据结构和算法、以及高效的资源释放机制。通过这些方法,开发者可以显著提升应用的性能和用户体验。
|
1月前
|
监控 算法 Android开发
安卓应用开发中的内存优化策略
【2月更文挑战第30天】随着移动设备性能的不断提升,用户对应用程序的体验要求越来越高。在安卓应用开发中,内存管理是影响应用性能和用户体验的关键因素之一。本文将探讨针对安卓平台的内存优化技巧,包括避免内存泄漏、合理使用数据结构和算法、优化图片资源处理等策略,旨在帮助开发者提升应用性能和稳定性。
19 1
|
7月前
|
存储 Linux Apache
Apache IoTDB开发之内存工具
IoTDB中的内存分为三部分:写内存,读内存和保留内存。写内存用于数据写入分配。三者的比例可以在配置文件中设置。
128 0
|
3月前
|
缓存 架构师 算法
Java内存溢出如何解决,Java oom排查方法,10个定位解决办法
在Java开发过程中,有效的内存管理是保证应用程序稳定性和性能的关键。不正确的内存使用可能导致内存泄露甚至是致命的OutOfMemoryError(OOM)。
|
4月前
|
存储 安全 数据安全/隐私保护
3.2 Windows驱动开发:内核CR3切换读写内存
CR3是一种控制寄存器,它是CPU中的一个专用寄存器,用于存储当前进程的页目录表的物理地址。在x86体系结构中,虚拟地址的翻译过程需要借助页表来完成。页表是由页目录表和页表组成的,页目录表存储了页表的物理地址,而页表存储了实际的物理页框地址。因此,页目录表的物理地址是虚拟地址翻译的关键之一。在操作系统中,每个进程都有自己的地址空间,地址空间中包含了进程的代码、数据和堆栈等信息。为了实现进程间的隔离和保护,操作系统会为每个进程分配独立的地址空间。在这个过程中,操作系统会将每个进程的页目录表的物理地址存储在它自己的CR3寄存器中。当进程切换时,操作系统会修改CR3寄存器的值,从而让CPU使用新的页
50 0
3.2 Windows驱动开发:内核CR3切换读写内存
|
5月前
|
存储 安全 API
3.5 Windows驱动开发:应用层与内核层内存映射
在上一篇博文`《内核通过PEB得到进程参数》`中我们通过使用`KeStackAttachProcess`附加进程的方式得到了该进程的PEB结构信息,本篇文章同样需要使用进程附加功能,但这次我们将实现一个更加有趣的功能,在某些情况下应用层与内核层需要共享一片内存区域通过这片区域可打通内核与应用层的隔离,此类功能的实现依附于MDL内存映射机制实现。
56 0
3.5 Windows驱动开发:应用层与内核层内存映射
|
5月前
|
安全 Windows
3.3 Windows驱动开发:内核MDL读写进程内存
MDL内存读写是一种通过创建MDL结构体来实现跨进程内存读写的方式。在Windows操作系统中,每个进程都有自己独立的虚拟地址空间,不同进程之间的内存空间是隔离的。因此,要在一个进程中读取或写入另一个进程的内存数据,需要先将目标进程的物理内存映射到当前进程的虚拟地址空间中,然后才能进行内存读写操作。
41 0
3.3 Windows驱动开发:内核MDL读写进程内存
|
5月前
|
存储 缓存 Linux
linux下定位多线程内存越界问题实践总结
linux下定位多线程内存越界问题实践总结
|
6月前
|
缓存 Shell C语言
用 TDengine 3.0 碰到“内存泄露”?定位问题原因很关键
在本篇文章中,我们将从 GitHub 上的一个关于内存泄漏的 issue入手,和大家探讨下导致内存泄漏的原因,以及如何避免和定位内存泄漏。
104 0