Chinaunix首页 | 论坛 | 博客
  • 博客访问: 658461
  • 博文数量: 175
  • 博客积分: 2457
  • 博客等级: 大尉
  • 技术积分: 1488
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-13 20:31
文章分类

全部博文(175)

文章存档

2012年(22)

2011年(153)

分类: 嵌入式

2011-07-28 21:25:12

在C、C++编程中,堆(Heap)和栈(Stack)是分配内存空间,存放数据的两个重要地点。一般的,使用malloc或new关键字分配的内存空间保存在堆中,而局部变量、或者函数的参数,都是保存在栈中。因此,当一个程序中递归的数量很多时,栈空间往往不够,最终造成内存溢出。本文介绍了在DSP服务线程中因栈控件不够而可能导致的问题,以及如何解决它们。

介绍

在DSP中,总是出现一些可以归咎于人品问题的灵异现象(程序跑得好好的却自动重启,或者运行若干次后就死机了),这些问题里,又有多少可以归咎于栈空间太小呢?

这真是一个令人头痛却又不得不引起重视的事。我们在.XS文件中的getStackSize()中返回一个很大的值来为DSP/BIOS中的Codec 算法分配栈空间,因此,最好的办法就是返回一个足够大的值(别太大,否则还是会崩溃的),来避免因栈不够导致的灵异事件而抓狂的。

最简单的解决办法

最简单的解决办法当然是在getStackSize中返回一个很大很大的值,越大越好,大得可以放下一部720P的小强的文件。不过这也许会让你的同事狠狠抽你一顿(嵌入式系统本来空间就有限)。因此,我们需要精确地知道这个值是多少。也许8K,16K的空间能满足你的要求吧。哦也

来,让我们来看看用了多少动态栈

如果使用CE2.0及其以后版本,我们可以使用 DEBUG=2  程序名 grep stack来查看倒地使用了多少动态栈空间:

root@146.252.161.13:~/r/ce-h18x# CE_DEBUG=2 ./app.out | grep stack [DSP] @0,051,117tk: [+4 T:0x8fa463cc] OT - Thread_create > name: "videnc_copy#0", pri: -1, stack size: 1024, stack seg: 0 [DSP] @0,065,397tk: [+4 T:0x8fa463cc] OT - Thread_create > name: "viddec_copy#1", pri: -1, stack size: 1024, stack seg: 0 @0,641,660us: [+5 T:0x4003a6d8] CE - Engine_deleteNode(0x3f998): algName = videnc_copy, algHandle = 0x8fa47398, stack size = 1024, stack used = 731(72%) @0,644,959us: [+5 T:0x4003a6d8] CE - Engine_deleteNode(0x3fae0): algName = viddec_copy, algHandle = 0x8fa47ce0, stack size = 1024, stack used = 739(73%) 修改动态栈分配

我们可以在Codec列表中为每一个算法线程制定stackSize值:

Server.algs = [ {name: "h264enc", mod: H264ENC,groupId:0,threadAttrs: { stackSize: 65536, stackMemId: 0, priority: Server.MINPRI + 1} }, {name: "h264dec", mod: H264DEC,groupId:1,threadAttrs: { stackSize: 65536, stackMemId: 0, priority: Server.MINPRI + 1} }, ]; // increase the stack size for the system thread as well Server.threadAttrs.stackSize = 65536;

再看看静态栈吧

先说说调用图(call graph,啥东东?因该是调用了哪些函数、变量吧)。我们知道,变量分动态和静态的,因此,一个静态调用图描述了所有可能的调用,而动态调用图则显示那些被实际调用的操作。因此,上面获得的动态调用栈是很精确D。话说回来,它仅仅是精确到运行到某过程中使用的栈大小,而没有考虑到一些尚未运行到的地方(例如某个递归调用,这将分配大量的栈空间)。

通常,一个静态调用图包括了所有可能发生的操作。因此,如果能搞定静态的栈大小,动态就自然OK了。

我们可以使用一个工具()来计算它:

C:\dir>ofd6x -x -g ex.out | call_graph Reading from stdin ... Call Graph for ex.out **************************************************** _c_int00 : wcs = 1240 | __args_main : wcs = 1240 | | _main : wcs = 1232 | | | _cond_is_false : wcs = 1216 | | | | _output : wcs = 1208 | | | | | _printf : wcs = 1176 | | | | | | __printfi : wcs = 1160 | | | | | | | __pproc_fflags : wcs = 0 | | | | | | | __pproc_fwp : wcs = 40 | | | | | | | | _atoi : wcs = 0 . . .

上面那个图中的wcs(worst case stack 最坏情况的栈)就是调用图中需要使用的栈空间的总大小。

小节

从没见过有人把栈的初始空间设置成大于32K的,所以不要把你的栈设得太大,优化你的程序,少用递归吧。

多分析分析动态栈和静态栈,注意每个方法中的栈空间申请。

阅读(1075) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~