概要设计
Switch#show memory region detail Level 1 Heap:
max block 3979384, free 4946320 bytes, total alloc 2320 blocks(231016592 bytes) Level 2 Heap:
total bytes: 124716456, total blocks 106,
current free bytes: 98285112, max block 81632496
Memory utilization 47%(Image 7%, Region 17%, Heap 38%/87%, Msg buffer 0%/3%)
[* 0 BASE]Size: 32 Current:22721 Max: 22789 Total: 65536 Range [0xdce8a80,0xdf68a80) [* 1 BASE]Size: 64 Current:19015 Max: 19053 Total: 65536 Range [0xdf68a80,0xe3e8a80) [* 2 BASE]Size: 128 Current:13478 Max: 13489 Total: 65536 Range [0xe3e8a80,0xec68a80) [- 3 BASE]Size: 256 Current: 8192 Max: 8192 Total: 8192 Range [0xec68a80,0xee78a80)
[* EXTEND( 1/ 10)] Current:17018 Max: 17019 Total: 29741 Range [0x73571e8,0x7ad4158)@002c84d4 [* 4 BASE]Size: 512 Current: 2270 Max: 2273 Total: 8192 Range [0xee78a80,0xf288a80) [* 5 BASE]Size: 1024 Current: 1023 Max: 1024 Total: 1024 Range [0xf288a80,0xf38aa80)
[+ EXTEND( 1/ 12)] Current: 165 Max: 171 Total: 6685 Range [0x65bd8f8,0x6c521e8)@002dc1fc [* 6 BASE]Size: 2048 Current: 509 Max: 512 Total: 512 Range [0xf38aa80,0xf48ba80)
[+ EXTEND( 1/ 13)] Current: 2630 Max: 2631 Total: 3579 Range [0x6c521f8,0x73571d8)@00379ee4
每个内存池的信息占一行,相关信息详述如下:
1、行首标记*表示当前使用,即系统收到该尺寸的内存分配请求时,从该池中分配内存,每个尺寸只有一个当前使用的内存池;行首标记-表示该池目前已经没有空闲块可供分配;行首标记+表示备用;
2、EXTEND表示扩展池,BASE表示基本池;
3、Range表示该内存池占用的内存地址,扩展池后的@XXXXXX表示触发创建扩展池的指令地址;
4、扩展池为当前备用状态,并且Current为0时,将被销毁。
max的值超过total的值是正常的;但是在配置没有增加或增加后又删除的情况下,某个大小的内存current alloc值持续大幅度(>10)增长则可能有问题;使用命令show memory region num可以打印出来具体大小的内存块的上一次操作情况。例如show memory region 2表示128字节内存快的使用情况,依此类推: Switch#show mem reg 2 information of rank 2:
Size: 128 Current alloc: 64 Max alloc: 90 Total: 4096
Buffer: 0x033a61e0(128) free at 0x00536e04 Buffer: 0x033a6268(128) free at 0x00536e04 ??
其中free表示上一次操作为释放操作,后面是执行释放操作的指令地址,alloc表示分配操作,其它则表示出现了错误。
2.2 内存泄漏
怀疑某个操作造成内存泄漏时,可以通过不停执行该操作,然后比较前后show memory region rank命令的执行结果来确认是否有内存泄漏出现。当某个region中内存块很多、难以分辨时,可以将操作前后该命令的执行结果保存为文本文件,使用Beyond Compare等比较工具进行比较,判断是否有内存泄漏。
2.3 内存重复释放
内存重复释放错误本质是应用程序释放了内存块后仍然保持着对块的引用。只有记录内存块所
273935858.doc Version1.4T (错误!未指定书签。) Page 6 of 27
概要设计
有历史释放点,才能准确定位内存块重复释放错误。VOS内存管理能够通过记录内存块的上一次释放点和当前状态,可以发现绝大多数重复释放问题:应用程序试图释放一个已经“空闲”的内存块,说明存在重复释放问题,上次释放点和本次释放点具有参考价值。 出现内存重复释放错误时,一般存在下述几种可能的操作序列:
1、 A分配得到a,A释放a,A释放a(错误被挂起:两次free都是A) 2、 A分配得到a,A释放a,B分配得到a,A释放a(错误无法识别),B释放a(正确却被挂
起:last free是A,这次是B)
3、 A分配得到a,A释放a,B分配得到a,B释放a,A释放a(错误被挂起:last free是B,
这次是a)
4、 A分配得到a,A释放a,A修改a指向的内存(破坏了空闲块链表),B试图分配(最坏的
情况,由于链表被破坏而产生异常,可以有限规避)
2.4 内存被非法改写
在我们的系统中目前没有有效办法准确定位内存被改写错误,尤其是“野指针”造成的错误。代码走读、单元测试等软件工程手段能够提高代码质量,从而减少内存被非法改写错误的发生。 某些数组越界访问造成内存被非法改写错误可以通过下列手段寻找线索:
全局变量被非法改写:在map中找到被改写的全局变量的位置,查看它的低地址方向是否有数据变量,有则可以检查该数组是否存在写越界的情况。
VOS内存管理分配得到的内存块被改写:内存块前端保存了内存池管理信息,VOS会定期检查该信息的正确性,当块前端的控制信息错误时,可能是该块低地址相邻的块内存写越界造成,系统会将前一个块的上次操作(分配、释放)以日志形式报告出来,供分析问题。
2.5 VOS内存管理关键日志信息
2.5.1
严重报错日志
%MEM-3-MALLOC_BADLINK [hex]:Bad free list of block [blk], last operated at [pc], previous block last operated at [prevpc]
系统从内存池分配内存时,发现空闲链表被破坏。[hex]表示内存分配操作的指令地址,[blk]表示内存块地址,[pc]表示被破坏的内存块上次操作地址,[prevpc]表示前一内存块上次操作地址。该日志提示系统出现了double free类错误或前一内存块写越界。
%MEM-6-MALLOC_INFO Data from [dig] bytes offset from block: [data1] [data2] [data3] [data4] 本日志伴随上一条日志出现,用于输出被破坏的内存块附近的信息。
%MEM-4-REGION_REBUILD Region [rgn](size = [sz]) was crashed, start rebuilding...
%MEM-4-REGION_REBUILD_COMPLETE Region [rgn] has been successfully rebuilt in [time] seconds, [nbrblks] block(s) found, [nbrfree] block(s) freed during rebuilding
这两条日志提示系统试图重建被破坏的内存池,如果两条日志成对出现,说明系统重建内存池成功,这样系统有较大概率继续正常运行;如果仅出现第一条日志则系统可能出现严重错误。 %MEM-3-FREE [pc]:free error, bad pointer [blk]
本日志提示系统中有应用程序试图释放一个从未分配过的指针。这是一种错误行为,但其释放行为本身不会对系统造成不良影响。
%MEM-3-FREE [pc]:free error, buffer [blk] crashed, alloced from [pc]
本日志提示系统中有应用程序释放内存时,内存块的相关控制信息被非法改写,这一般是前一内存块写越界或非法内存改写导致。
%MEM-6-PREVBLOCK: Block([blk]) previous block last alloc at pc [pc]
273935858.doc Version1.4T (错误!未指定书签。) Page 7 of 27
概要设计
%MEM-6-PREVBLOCK: Block([blk]) previous block last free at pc [pc] 这两条日志伴随free error日志出现,提示前一内存块上次使用地址。
%MEM-3-DOUBLE_FREE [pc]:free error, double free ptr [blk], last time free at [lastpc]
本日志提示系统出现了double free类错误,pc表示本次释放地址,lastpc表示上次释放地址。
2.5.2 信息提示日志
%STATICMEM-6-REFILL:Static memory region refilled at [hex]
本日志用于报告系统静态内存区溢出的情况,hex表示触发静态内存区溢出的内存分配指令地址。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。
%PARTMEM-4-REFILL:Partion [hex] refilled
本日志用于报告系统分区内存溢出的情况,hex表示溢出的分区id。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。 %MEM-6-EXT_REGION_CREATE [hex1]: Create extend region for region [dig1] rank [dig2], [dig3] blocks [dig4] bytes
本日志用于报告当前系统创建了一个扩展内存池,hex1是触发创建扩展内存池的指令地址,dig1和dig2代表扩展池索引信息,dig3表示该池包含的块数量,dig4表示该池消耗的总字节数。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。
%MEM-6-EXT_REGION_DESTORY [hex1]: Destory extend region for region [dig1] rank [dig2] 本日志用于报告当前消耗了一个扩展内存池,hex1是触发销毁扩展内存池的指令地址,dig1和dig2代表扩展池的索引信息。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。
%MEM-6-EXT_REGION_CREATE_CONCURRENT: Try to create extend region for region [dig1] rank [dig2] cocurrently with another task
当多个任务试图创建相同索引的扩展内存池时,系统会报告本日志,其中dig1和dig2代表扩展池的索引信息。报告该日志的目的是收集系统统计信息,以便于更好的优化;触发该日志的事件不会对系统运行产生任何不良影响。
%MEM-4-EXT_REGION_DECREASING_SIZE: Create extend region[dig1/dig2] for [dig3] blocks failed, total memory [dig4], try half
本日志用于报告当前试图创建扩展内存池时发生失败,这时系统会尝试折半创建,即创建一个包含[dig3]/2个块的内存池。该日志提示系统处于内存不足的压力之下,可尝试减少系统负载以使降低内存消耗;一半在压力测试时容易出现。
273935858.doc Version1.4T (错误!未指定书签。) Page 8 of 27
概要设计
3. 任务信息显示
3.1 任务信息
在系统运行过程中,可能出现一些异常情况,比如说某个功能不再有效,这有可能是某个任务因出现异常情况而不再运行有关。可以使用命令show task来察看任务的情况(为了阅读方便,略去了一些非典型的任务): Switch#show task info
CPU utilization for one second: 1%; one minute: 1%; five minutes: 1%
NAME ENTRY TID PRI PC Stk Ptr SP lmt ERR.NO ST invoked CPU ---------------------------------------------------------------------------- ARL 15c0a4 03c6c538 128 6bc9b8 03c6c488 03c6a648 000000 P 38 0.00 LINK 1477c8 03c6a190 128 6bd0d8 03c6a0d8 03c682a0 3d0004 PD 181334 0.00 STAT 1619a0 03c55798 128 6bc9b8 03c556d8 03c538a8 3d0004 PD 14061 0.00 IDLE 534b38 03d1f078 255 534b44 03d1f020 03d1ec80 000000 R 307346 99.23 _TM_ 53117c 032b0e20 055 6c0e14 032b0db8 032a9240 000000 D 133717 0.00 TLII 11efe8 03268bf8 128 6bc9b8 03268b80 03259018 000000 P 6307 0.11 MYIP 2d7bb8 031c8e68 128 6eed58 031c8d38 031c6a88 000000 P 2679 0.00 SLOG 544ae8 0299a200 128 6eed58 0299a140 02996620 000000 P 40 0.00 L3AG 037480 026c2eb8 180 6c0e14 026c2e78 026bf2d8 000000 D 13356 0.00 THAL 020098 026bec18 128 6eed58 026beb00 026bb038 000000 P 1675 0.00 _QOS 56dcf0 026ba9d8 128 6c0e14 026ba9a8 026b6df8 000000 D 45 0.00 tty0 5498e8 02598948 128 6bd0d8 02598310 02588d68 3d0002 R 3776 0.30 CHCK 534f4c 0257ee28 180 6c0e14 0257ede0 0257d248 000000 D 215 0.00 SNMT 591cfc 0257cc10 128 6c0e14 0257cbc8 02579030 000000 D 45 0.00 INTR 000000 00a60268 000 000000 00000000 00000000 000000 134298 0.03
上面例子中,最上面一行是总CPU占用率,分别是最近1秒、1分钟、5分钟的系统平均占用率;然后是每个任务的信息,其各项含义如下: 名称 含义 NAME 任务名称 ENTRY 任务入口地址 TID 任务的标识符 PRI 任务的优先级 PC 任务的当前指令地址 SP Ptr 任务当前堆栈指针 SP Lmt 任务当前栈顶指针 ERRORNO 当前任务的错误码 ST 任务的当前状态(P表示阻塞、S表示挂起、R表示就绪,D表示有等待时间) invoked 任务切入次数 CPU 任务CPU占用率,只具有定量的意义 不同的版本、不同的设备类型,上面这些值不会相同。系统正常运行的情况下,应满足下列条件:
273935858.doc Version1.4T (错误!未指定书签。) Page 9 of 27
概要设计
a) 只有线卡的NATM任务状态为S;如果其它任何一个任务状态持续为S,该任务就可能有
问题
b) 任何一个任务的SP Ptr都比位于SP Lmt与TID之间。
3.2 特定任务的堆栈
3.2.1
直接使用show task查看特定任务的堆栈
当怀疑某个任务不正常时,可以通过查看该任务的堆栈来帮助定位问题。使用show task
CPU utilization for one second: 2%; one minute: 2%; five minutes: 2%
P - Pending D - Delay R - Ready S - Suspend E - Estimated NAME ENTRY TID PRI PC Stk Ptr SP lmt ERR.NO ST CPU invoked ---------------------------------------------------------------------------- RPCS 36fe00 0a6c75e0 060 7da714 0a6c6c10 0a6b7890 3d0004 PD 0.00 576962 Gauge of sp reset from 0a6c5120 to 0a6c6810,Max stack usage 15 task RPCS pc = 007da714 ra = 0032bc98 call procedure-- 0x007da714-- [PC]
0x007c1b6c-- [SP 0a6c6c70] 0x0032cc1c-- [SP 0a6c6cb0] 0x0036fe88-- [SP 0a6c6ce0] 0x0032f4bc-- [SP 0a6c73e0] 0x007993ac-- [SP 0a6c7590]
last switched in at f75abda, now f75ac1c Stack for task RPCS(512 bytes)
0a6c6c10: 00000000 00000000 00000000 01110000 0a6c6c20: 00000000 0a8c7900 00000000 0a8c7900
系统记录了每个任务堆栈使用的最大深度,每次show task时如果当前堆栈深度低于最大深度,则会清空最大深度记录,这时会输出“Gauge of sp reset from xxx to xxx”;“Max stack usage 15”表示之前最大堆栈深度为总堆栈的15%。
3.2.2 早期版本使用show memory查看特定任务的堆栈
早期libsys版本不支持show task
031c8d30: 0290AACC 00000000 031C8D70*006EED58 ...........p.n.X 031c8d40: 00000000 00000000 00000000 00000000 ................ 031c8d50: 08000000 00000000 00000000 031C8DB0 ................ 031c8d60: 00000010 FFFFFFFF 0290AAC8 031C8DA0 ................ 031c8d70: 031C8D90*006BB694 00000000 00000000 .....k.......... 031c8d80: 00000000 00840000 0290AAC8 031C8DA0 ................
273935858.doc Version1.4T (错误!未指定书签。) Page 10 of 27