栈让我用完了

问题:从事一个项目的开发已经好几个月了,多了一个模块就task_create()一下。昨天当我将串口的代码加入到工程文件中进行编译的时候,(还没有调用串口驱动程序,只是初始化一下),但是导致的结果是程序运行不是预期的结果。


解决方法:靠人品

本来想从系统的__start处,彻底的想追踪一下代码的运行情况,但是我潜意识告诉我,随便从app层来下个断点试试,我就在不同的任务创建处,设置了断点。查看一下它们的返回情况,在一个任务创建的时候,返回值居然是-1。我于是追踪了一下该任务创建的过程,发现mmalloc()是失败的。才发现需要的栈空间不够用。于是我减少了栈空间的申请。最终该解决了。再后来,我还把串口需要的缓存区也减少了(txbuffer和rxbuffer减少到64字节)。


趁着喜悦的心情,我就在网上收索了一下前人的经验,在此加深一下印象。。。。。


linux下共使用了四种堆栈:

一    系统引导初始化临时使用的堆栈

二    进入保护模式后提供内核程序始化使用的堆栈,该堆栈也是后来任务0使用的用户态堆栈

三    每个任务通过系统调用,执行内核程序时使用的堆栈,称之为任务的内核态堆栈,每个任务都有自己独立的内核态堆栈

四    任务在用户态执行的堆栈,位于任务(进程 )逻辑地址空间近末端处
使用多个栈或在不同情况下使用不同栈的主要原因

(一)由于从实模式进入保护模式,使得CPU对内存寻址访问方式发生了变化,因此需要重新设置堆栈区域

(二) 为了解决不同CPU特权级共享使用堆栈带来的保护问题,执行0级的内核代码和执行3级的用户代码需要使用不同的栈。当一个任务进入内核态运行时,就会使用其TSS段中给出的特权级0的堆栈指针tss.ss0.tss.esp0,即内核栈,原用户栈指针会保存在内核栈中,而当从内核态返回用户态时,就会恢复使用用户态的堆栈


他在内核中使用了一个深度函数调用(多层嵌套的函数),但没有实现预定的效果,但如果把嵌套去掉,函数就没问题了。当时我也没有多想,就回答可能是编译器的问题。回来后头脑中又浮现出这个问题,突然想到内核栈,觉得这个问题的原因应该出在内核栈上。下面简要介绍下内核的知识。

用户空间运行的程序可以从用户空间的栈上分配大量的空间来存放变量或数组、大的结构体。之所以可以这么做,是因为用户空间栈本身比较大,而且还能动态增长。进程的内核栈即不大也不能动态增长;它在32位机上的内核栈为8KB,而64位机是16KB。

每个进程都有自己的内核栈。进程在内核执行期间的每个调用链必须放在自己的内核栈上。中断处理程序也使用配它们打断的进程堆栈。这就意味着,在最恶劣的情况下,8KB的内核栈可能会被多个函数的嵌套调用链和几个中断程序来共享。呵呵,显然深度的嵌套会导致溢出了。

节省内核栈的方法有:减少局部变量、大型数组和结构体、嵌套调用链。


Linux下更改栈空间大小

Linux下默认的栈空间大小是10M,可以通过ulimit -s进行查看,不同的Linux发行版本可能不太一样。下面介绍 栈空间大小修改方法。
 
临时修改方法:
ulimit -s <新的栈空间大小>
 
永久修改方法:
1. 可以修改配置文件/etc/security/limits.conf
2. 可以将ulimit -s命令放到/etc/profile中,在任何用户启动的时候调用


ulimit的参数说明:

选项 [options]含义例子
-H设置硬资源限制,一旦设置不能增加。ulimit – Hs 64;限制硬资源,线程栈大小为 64K。
-S设置软资源限制,设置后可以增加,但是不能超过硬资源设置。ulimit – Sn 32;限制软资源,32 个文件描述符。
-a显示当前所有的 limit 信息。ulimit – a;显示当前所有的 limit 信息。
-c最大的 core 文件的大小, 以 blocks 为单位。ulimit – c unlimited; 对生成的 core 文件的大小不进行限制。
-d进程最大的数据段的大小,以 Kbytes 为单位。ulimit -d unlimited;对进程的数据段大小不进行限制。
-f进程可以创建文件的最大值,以 blocks 为单位。ulimit – f 2048;限制进程可以创建的最大文件大小为 2048 blocks。
-l最大可加锁内存大小,以 Kbytes 为单位。ulimit – l 32;限制最大可加锁内存大小为 32 Kbytes。
-m最大内存大小,以 Kbytes 为单位。ulimit – m unlimited;对最大内存不进行限制。
-n可以打开最大文件描述符的数量。ulimit – n 128;限制最大可以使用 128 个文件描述符。
-p管道缓冲区的大小,以 Kbytes 为单位。ulimit – p 512;限制管道缓冲区的大小为 512 Kbytes。
-s线程栈大小,以 Kbytes 为单位。ulimit – s 512;限制线程栈的大小为 512 Kbytes。
-t最大的 CPU 占用时间,以秒为单位。ulimit – t unlimited;对最大的 CPU 占用时间不进行限制。
-u用户最大可用的进程数。ulimit – u 64;限制用户最多可以使用 64 个进程。
-v进程最大可用的虚拟内存,以 Kbytes 为单位。ulimit – v 200000;限制最大可用的虚拟内存为 200000 Kbytes。

参考文献:

http://tech.ddvip.com/2008-09/122095404362368.html

http://os.51cto.com/art/200912/168376.htm

http://blog.chinaunix.net/uid-22197900-id-3038004.html




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉树的中序遍历可以用来实现非递归程序,具体实现步骤如下: 1. 创建一个,并将根节点入。 2. 当不为空时,执行以下操作: a. 取出顶元素,如果该元素有左子树,则将左子树入。 b. 如果该元素没有左子树或者左子树已经遍历了,则输出该元素的值,并将右子树入。 3. 当所有节点都被遍历了,中序遍历结束。 下面是该算法的C语言实现代码: ```c #include <stdio.h> #include <stdlib.h> // 二叉树的结构体定义 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 的结构体定义 typedef struct StackNode { struct TreeNode* node; struct StackNode* next; } StackNode; // 创建一个空 StackNode* createStack() { return NULL; } // 判断是否为空 int isEmpty(StackNode* top) { return top == NULL; } // 元素入 void push(StackNode** top, TreeNode* node) { StackNode* new_node = (StackNode*)malloc(sizeof(StackNode)); new_node->node = node; new_node->next = *top; *top = new_node; } // 元素出 TreeNode* pop(StackNode** top) { if (isEmpty(*top)) { return NULL; } TreeNode* res = (*top)->node; StackNode* temp = *top; *top = (*top)->next; free(temp); return res; } // 中序遍历二叉树的非递归实现 void inorderTraversal(TreeNode* root) { if (root == NULL) { return; } StackNode* stack = createStack(); while (root != NULL || !isEmpty(stack)) { while (root != NULL) { push(&stack, root); root = root->left; } root = pop(&stack); printf("%d ", root->val); root = root->right; } } // 主函数 int main() { // 创建二叉树 TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode)); root->val = 1; root->left = (TreeNode*)malloc(sizeof(TreeNode)); root->left->val = 2; root->left->left = NULL; root->left->right = NULL; root->right = (TreeNode*)malloc(sizeof(TreeNode)); root->right->val = 3; root->right->left = (TreeNode*)malloc(sizeof(TreeNode)); root->right->left->val = 4; root->right->left->left = NULL; root->right->left->right = NULL; root->right->right = (TreeNode*)malloc(sizeof(TreeNode)); root->right->right->val = 5; root->right->right->left = NULL; root->right->right->right = NULL; // 中序遍历二叉树 inorderTraversal(root); return 0; } ``` 这段代码中,我们定义了一个`StackNode`结构体表示中的节点,该结构体包含一个指向二叉树节点的指针`node`和一个指向下一个节点的指针`next`。我们还定义了一个`createStack()`函数用来创建一个空,一个`isEmpty()`函数判断是否为空,一个`push()`函数将元素入,一个`pop()`函数将元素出。最后,我们定义了一个`inorderTraversal()`函数用来实现中序遍历二叉树的非递归程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值