探究Linux进程及线程堆栈专题<一>

  “你定义了那么多全局变量,系统才给你分配了几百KB,这样做是不是太耗内存了?”,一同学问道。

  老早就听说嵌入式系统各种资源有限啊,不能分配大空间啊要注意节约资源之类的(。。。貌似米神4的配置要完爆我的thinkpad了。。。)。那是不是全局变量的使用真的会占用很大系统内存,而系统真的才分配几百KB空间给我呢?

  我不信,所以我要尝试一下:

  全局变量,肯定是要占用内存的,但无论是不是全局变量,只要是已定义的变量都会占用内存,这个和是否是全局的没啥关系,只是占用的区域不一样而已(详见APUE存储器安排 P153)。

系统怎么可能就给我几百K的空间,那我的安卓机上的QQ咋动不动就几十兆的资源占用率?

  不扯淡了,下面就是我的探究内容。



获得当前进程的堆栈的最大字节长度 :

#define getLimit(name) get_limits(#name,name)
//这个#是字符串创建符,可以在宏中创建字符串

//只是打印判断是具体数值还是字符串
void print_infinite(rlim_t t)
{
    if(RLIM_INFINITY == t)
    {
        printf("%14s  ","infinite");
    }
    else
    {
        printf("%14ld  ",t/1024/1024);
    }

}

//封装了获取特定类型数据的最大值
static void get_limits(char *name,int resource)
{
    struct rlimit limit;

    if(getrlimit(resource,&limit) != 0)
    {
        printf("get limit error  %s\n",strerror(errno));
    }

    printf("%-14s  ",name);

    print_infinite(limit.rlim_cur);

    print_infinite(limit.rlim_max);

    putchar(‘\n‘);
}

//入口函数,得到进程的堆栈最大值
void GetProcessHeapAndStackLimitSize()
{
    printf(PARTING_LINE);

    printf("%-14s   ","Name");
    printf("%13s   ","LimCur(MB)");
    printf("%13s   \n","LimMax(MB)");

    //RLIMIT_DATA   数据段的最大字节长度: 初始化数据、非初始化及堆的总和
    getLimit(RLIMIT_DATA);

    //RLIMIT_STACK 栈区的最大字节长度
    getLimit(RLIMIT_STACK);
    printf("\n");

}

用来测试获取数据是否正确的一个小方法:

递归调用,每调用一次消耗系统 栈区  大小1M。自动变量以及每次函数调用时所需保存的信息都放在区。

//用来测试,是否是堆的最大值
void GetStackSize()
{
    static int i = 1;

    char xxx[1024*1024] ;///1MB

    printf("now i is  :  %d\n",i);

    GetStackSize(++i);
}

写个main函数,先调用GET方法,获得堆栈值再调用测试函数结果如下:

===============================   GetProcessHeapAndStackLimitSize  =================================  

Name                LimCur(MB)      LimMax(MB)
RLIMIT_DATA           infinite        infinite
RLIMIT_STACK                 8        infinite  

now i is  :  1
now i is  :  2
now i is  :  3
now i is  :  4
now i is  :  5
now i is  :  6
now i is  :  7
Segmentation fault (core dumped)

infinite可以理解为不限制,从结果可以看出,当前进程的堆区(其实,这种方法获得的不是严格意义上的堆区,这里获得的是包括初始化数据、非初始化数据及堆区的总和)的大小是

没有限制的,而栈区系统却仅仅分配了8M的空间,也就是说,当前进程下你能使用的局部变量等总和不能超过8M,否则系统就会出现错误(Segmentation Fault)。

如果果真如此的话,那我在main函数里直接定义char xxx[8*1024*1024]会是什么情况呢?显然的,什么都不执行就段错误了。

8M显然是不够我用的,特别是当我需要各种缓冲区时,那我该如何“扩容”呢?或者我系统确实内存有限不能让某些应用程序占用过多内存,那么我如何限制它的内存使用呢?

下面就是修改系统 默认配置的方法:

//封装了设置特定类型数据的最大值
static void set_limits(char *name,int resource,rlim_t cur,rlim_t max)
{
    struct rlimit limit;

    limit.rlim_cur = cur;
    limit.rlim_max = max;

    if(setrlimit(resource,&limit) != 0)
    {
        printf("get limit error  %s\n",strerror(errno));
    }
    else
    {
        printf("%s %s  OK \n",__func__,name);

    }
}

void SetProcessHeapAndStackLimitSize()
{
    printf(PARTING_LINE);

    //RLIMIT_DATA   数据段的最大字节长度: 初始化数据、非初始化及堆的总和
    rlim_t pref = 10*1024*1024;

    setLimit(RLIMIT_DATA,pref,pref*2);

    //RLIMIT_STACK 栈区的最大字节长度
    setLimit(RLIMIT_STACK,pref*2,pref*4);    

}

这样设置的结果会什么什么样子呢?我们可以先设置之,然后再重新调用GET方法看看是否设置成功。

//主函数
int main(int argc ,char **argv)
{

    GetProcessHeapAndStackLimitSize();

    //GetStackSize();//没有重新设置之前,返回7就崩溃了

    SetProcessHeapAndStackLimitSize();

    GetProcessHeapAndStackLimitSize();

    GetStackSize();//设置后,返回19就崩溃了

  ruturn 0;
}

结果如下:

===============================   GetProcessHeapAndStackLimitSize  =================================  

Name                LimCur(MB)      LimMax(MB)
RLIMIT_DATA           infinite        infinite
RLIMIT_STACK                 8        infinite  

===============================   SetProcessHeapAndStackLimitSize  =================================  

set_limits RLIMIT_DATA  OK
set_limits RLIMIT_STACK  OK 

===============================   GetProcessHeapAndStackLimitSize  =================================  

Name                LimCur(MB)      LimMax(MB)
RLIMIT_DATA                 10              20
RLIMIT_STACK                20              40  

now i is  :  1
now i is  :  2
now i is  :  3
now i is  :  4
now i is  :  5
now i is  :  6
now i is  :  7
now i is  :  8
now i is  :  9
now i is  :  10
now i is  :  11
now i is  :  12
now i is  :  13
now i is  :  14
now i is  :  15
now i is  :  16
now i is  :  17
now i is  :  18
now i is  :  19
Segmentation fault (core dumped)

恰如我们所料,修改参数成功,我们可以使用更多的栈区,也可以限制堆区的使用。

而当我们多次执行时却发现一个有趣的现象:虽然我们设置成功了,但重新运行程序后,系统还是会仅仅给我们分配8M,可见我们的这个改变仅仅是对当前进程的设置生效,那么如何对系统所有生效呢?见下文分解。

了解这些东西之后,我们有时可能会碰到程序无故挂掉,任何error信息都不打印,甚至GDB都不说问题出在哪里时,大伙可能得考虑一下,是否被系统限制了。

源码已上传。

探究Linux进程及线程堆栈专题<一>

时间: 2024-10-14 11:52:10

探究Linux进程及线程堆栈专题<一>的相关文章

Linux进程或线程绑定到CPU

Linux进程或线程绑定到CPU 为了让程序拥有更好的性能,有时候需要将进程或线程绑定到特定的CPU,这样可以减少调度的开销和保护关键进程或线程. 进程绑定到CPU Linux提供一个接口,可以将进程绑定到特定的CPU: #include <sched.h> int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask); int sched_getaffinity(pid_t pid, size_t cpu

Linux 进程、线程运行在指定CPU核上

/******************************************************************************** * Linux 进程.线程运行在指定CPU核上 * 说明: * affinity参数决定了进程.线程是否可在CPU多核之间切换,当然,并不是说就不进行 * 线程切换. * * 2017-9-22 深圳 龙华樟坑村 曾剑锋 *********************************************************

linux 进程 VS 线程

在进行编程模型选择时,总是要对进程和线程的优缺点进行对比,才能做出决定.这里对常用的对比纬度进行了总结,如有新发现,我会更新. linux 进程 VS 线程

Linux进程和线程的比较

进程与线程 参考:http://www.cnblogs.com/blueclue/archive/2010/07/16/1778855.html 首先比较Linux进程和线程的创建的区别,以此展开: 创建进程:(1)调用fork(),为子进程新建内核栈.pthread_info和task_struct,复制父进程的大部分的参数,采用写时复制(copy-on-write)辅助父进程的资源,修改子进程如pid.ppid等重要资源.(2)调用exec()为子进程分配地址空间,载入执行程序. 创建线程:

linux进程、线程(or子进程)、资源占用查看

#  linux进程.线程(or子进程).资源占用查看 查看进程: ps -ef | more  (-e:所有进程,-f:全格式) ++++++++++++++++++++++++++++++++++++ + UID :用户ID                     + + PID :进程ID                           + + PPID :父进程ID                                                 + + C :CPU占

windows和linux进程与线程的理解

对于windows来说,进程和线程的概念都是有着明确定义的,进程的概念对应于一个程序的运行实例(instance),而线程则是程序代码执行的最小单元.也就是说windows对于进程和线程的定义是与经典OS课程中所教授的进程.线程概念相一致的. 提供API,CreateThread()用于建立一个新的线程,传递线程函数的入口地址和调用参数给新建的线程,然后新线程就开始执行了. windows下,一个典型的线程拥有自己的堆栈.寄存器(包括程序计数器PC,用于指向下一条应该执行的指令在内存中的位置),

【Linux】第二章 Linux进程与线程(下)

4. Linux内核级线程与用户级线程 POSIX线程调度是一个混合模型,既支持用户级也支持内核级的线程.在创建线程时对contentionscope属性可设置为: PTHREAD_SCOPE_PROCESS.它表示新创建的线程与它所在的进程中的其他线程竞争处理器资源,等同用户级线程. PTHREAD_SCOPE_SYSTEM.说明新创建的线程就像内核级线程一样在全系统的范围内竞争处理器资源. (1) 内核级线程 线程的创建.撤销和切换等,都需要内核直接实现,即内核了解每一个作为可调度实体的线程

Linux进程与线程的区别

cnyinlinux 本文较长,耐心阅读,必有收获! 进程与线程的区别,早已经成为了经典问题.自线程概念诞生起,关于这个问题的讨论就没有停止过.无论是初级程序员,还是资深专家,都应该考虑过这个问题,只是层次角度不同罢了.一般程序员而言,搞清楚二者的概念,在工作实际中去运用成为了焦点.而资深工程师则在考虑系统层面如何实现两种技术及其各自的性能和实现代价.以至于到今天,Linux内核还在持续更新完善(关于进程和线程的实现模块也是内核完善的任务之一). 本文将以一个从事Linux平台系统开发的程序员角

操作系统:Linux进程与线程

这里是一部分内容,还会做修改. 一:目的及内容 学习fork(),exec,pthread库函数的使用,阅读源码,分析fork,exec,pthread_create函数的机理 代码实现: 进程A创建子进程B 子进程B与父进程A分别对应不同的可执行体:A打印Hello world,B实现sum累加 进程B具有三线程,主线程创建新的线程1实现sum累加(从1到参数x),线程2监控输入参数x 若输入x是非负整数,线程1开始计算:如果线程1正在计算前次程序,线程2的输入非负整数和最近一次的又不同,线程