1. 问题现象
在调试Am5728 + vxworks时,,同时加载算法模块DKM(.out)和通讯模块DKM(.out)文件时,发现有内存分配失败的打印,业务无法启动。
另外应用还有反馈,如果算法模块中定义了太多的静态变量,会造成通讯模块无法加载。
2. 定位过程
step 1. 排查出错地址在哪个区域?
仔细看了一下出错的地址0x50d440
,这个地址是落在Kernel System Virtual Memory
区域当中的。
整个Vxworks的地址空间划分如下:
我们使用adrSpaceShow()函数验证一下当前的单板地址空间配置是否符合:
-> adrSpaceShow
Global RAM Pool Info:
---------------------
Allocation unit size: 0x1000 4.0kB
Total size: 0x7c000000 1.9GB
Allocated: 0x751f000 117.1MB
Free: 0x74ae1000 1.8GB
Largest contiguous free block: 0x74ae1000 1.8GB
Shared User Virtual Memory Region Info:
---------------------------------------
Allocation unit size: 0x1000 4.0kB
Total size: 0x20000000 512.0MB
Allocated: 0 0.0
Free: 0x20000000 512.0MB
Largest contiguous free block: 0x20000000 512.0MB
RTP Private Virtual Memory Region Info:
---------------------------------------
RTP component included: Yes
RTP Address Space: Overlapped
RTP code region base: 0x80000000
RTP code region size: 0x60000000 1.5GB
Kernel System Virtual Memory Info:
----------------------------------
System Region Base: 0000000000
System Region Size: 0x20000000 512.0MB
Kernel Virtual Memory Pool Region Info:
---------------------------------------
Allocation unit size: 0x1000 4.0kB
Total size: 0x60000000 1.5GB
Allocated: 0x62ba000 98.7MB
Free: 0x59d46000 1.4GB
Largest contiguous free block: 0x59d46000 1.4GB
value = 0 = 0x0
总结:当前单板符合vxworks的地址空间模型,出错地址
0x50d440
范围确认在Kernel System Virtual Memory
。
step 2. 大胆尝试
出错信息block too big 1441480 bytes (0x8 aligned) in partition 0x50d440
,是提示分配空间太大。要么是内存池(Heap/Memory Partition)的空间不足,或者是要分配的空间太大超过了系统允许的最大限制。
partition 0x50d440
看起来这个地址是一个内存池地址,我们尝试来看看是不是?
我们找到了Memory Partition
的一些调试函数:
memShow( ) - show blocks and statistics for the current heap partition
memPartShow( ) - show available and allocated memory in specified partition
STATUS memShow
(
int type /* 0 = summary, 1 = list all blocks in the free list, */
/* 2 = list all sections */
)
STATUS memPartShow
(
PART_ID partId, /* memory partition ID */
int type /* 0 = statistics, 1 = statistics & list */
/* 2 = statistics & list & extra info */
)
尝试使用,地址的确是一个内存池的地址:
-> memPartShow(0x50d440,2)
LIST OF FREE BLOCKS:
number size addr
-------- ---------- ----------
Free block list truncated for printing (823 more)
LIST OF MEMORY SECTIONS ADDED TO THE PARTITION:
start addr size
---------- ----------
0x00524300 16748536
0x0051f300 20480
OPTIONS:
ALLOC_ERROR_EDR_WARN
ALLOC_ERROR_LOG
BLOCK_ERROR_EDR_WARN
BLOCK_ERROR_LOG
BLOCK_ERROR_SUSPEND
SUMMARY:
status bytes blocks avg block max block
-------- -------------- ---------- ---------- ----------
current
free 4425792 823 5377 1159880
alloc 12342712 877 14073 -
internal 408 2 204 -
cumulative
alloc 12347032 879 14046 -
peak
alloc 12343120 - - -
value = 0 = 0x0
这里的内存池大概16M,已经用了12M,剩余4M,最大连续空间为1.1M。的确存在内存分配不到的风险。
联想到Kernel System Virtual Memory
区域只有一个内存池Kernel Proximity Heap
,作用就是用来加载模块的。
我们在VIP工程中查看Kernel Proximity Heap
的大小:
#define KERNEL_PROXIMITY_HEAP_SIZE 0x1000000
刚好为16M,基本上肯定就是Kernel Proximity Heap
了。
总结:
0x50d440
确认是Kernel Proximity Heap
内存池地址,而且这个内存池的确存在分配不到1.4M内存的情况和现象吻合。
3. 结论
修改一个Kernel Proximity Heap
大小为32M的版本,给应用测试,测试ok,问题解决。
#define KERNEL_PROXIMITY_HEAP_SIZE 0x2000000