zoukankan      html  css  js  c++  java
  • 探究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
    ",strerror(errno));
        }
    
        printf("%-14s  ",name);
    
        print_infinite(limit.rlim_cur);
    
        print_infinite(limit.rlim_max);
    
        putchar('
    ');
    }
    
    
    
    //入口函数,得到进程的堆栈最大值
    void GetProcessHeapAndStackLimitSize()
    {
        printf(PARTING_LINE);
    
        printf("%-14s   ","Name");
        printf("%13s   ","LimCur(MB)");
        printf("%13s   
    ","LimMax(MB)");
    
    
        //RLIMIT_DATA   数据段的最大字节长度: 初始化数据、非初始化及堆的总和
        getLimit(RLIMIT_DATA);
    
        //RLIMIT_STACK 栈区的最大字节长度
        getLimit(RLIMIT_STACK);
        printf("
    ");
    
    
    
    }

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

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

    //用来测试,是否是堆的最大值
    void GetStackSize()
    {
        static int i = 1;
    
        char xxx[1024*1024] ;///1MB
    
    
        printf("now i is  :  %d
    ",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
    ",strerror(errno));
        }
        else
        {
            printf("%s %s  OK 
    ",__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都不说问题出在哪里时,大伙可能得考虑一下,是否被系统限制了。

    源码已上传。

  • 相关阅读:
    正则中[A-z]与[A-Za-z]的区别
    .Net Core 缓存方式(二)DistributedSqlServerCache实现(2)
    .Net Core 缓存方式(二)分布式缓存及MemoryDistributedCache 实现(1)
    anaconda安装后spyder打不开的解决方法
    Pandas
    CrawlSpider、分布式、增量式
    Scrapy之数据解析与数据持久化存储
    封装axios库
    vue全国省市选择vue组件
    html+jq实现全国省的单选,弹框输入input
  • 原文地址:https://www.cnblogs.com/xiaowenhu/p/3806102.html
Copyright © 2011-2022 走看看