thread线程栈size及局部变量最大可分配size

原创 2015年07月08日 17:20:16

进程是操作系统的最小资源管理单元, 线程是操作系统最小的执行单元。 一个进程可以有多个线程, 也就是说多个线程分享进程的资源,包括栈区,堆区,代码区,数据区等。

sundh@linhaoIPTV:~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31675
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31675
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

32bit x86机器上面,执行ulimit -a的命令, 可以看到

stack size              (kbytes, -s) 8192    这是否说明在线程中可以分配8M的局部变量(或者说分配7M的局部变量,还有1M的空间存储其他的局部变量或者寄存器状态信息(例如bp等)或者函数压栈信息等)

写代码验证如下:

//test2.cpp
#include <iostream>
#include <string.h>
#include <pthread.h>
#include <stdio.h>

using namespace std;

void* func(void*a)
{
    cout << "enter func" << endl;
    cout << "enter func" << endl;
    int b[1024*1024*2] = {0};
}

int main()
{
    int a[1024*1024*3/2]={0};
    pthread_t  pthread ;
    pthread_create(&pthread, NULL, func, NULL);
    cout << "This is a test" << endl;
    //pthread_join(pthread, NULL);
    return 0;
}
g++ -g -o test2 test2.cpp -lpthread
sundh@linux:~$ gdb test2
GNU gdb (GDB) 7.5-ubuntu
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/sundh/test2...done.
(gdb) r
Starting program: /home/sundh/test2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
[New Thread 0xb7cc1b40 (LWP 10313)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7cc1b40 (LWP 10313)]
func (a=0x0) at test2.cpp:10
10          cout << "enter func" << endl;
(gdb)

GDB调试结果如上。   main() 函数中分配1.5M的局部变量,是不会报错的, 但子线程中分配2M的局部变量,就会coredump。 可见,只能分配不大于2M的局部变量,但ulimit -a 查询到的stack size 为8M。


猜想:  线程只能分配不大于 1/4 大小的 stack size 给 局部变量, 这应该是操作系统的规定。(没在网络上面找到相关的文档说明)

那我们现在开始验证我们的猜想:


通过 ulimit -s命令修改默认的栈大小,  下面程序分配5M的局部变量, 也就是说线程栈的大小要 > 20M(5M*4)

//test1.cpp
#include <iostream>
#include <string.h>
#include <pthread.h>
#include <stdio.h>

using namespace std;

void* func(void*a)
{
    cout << "enter func" << endl;
    cout << "enter func" << endl;
    int b[1024*1024*5] = {0};
}

int main()
{
    int a[1024*1024*5]={0};
    pthread_t  pthread ;
    pthread_create(&pthread, NULL, func, NULL);
    cout << "This is a test" << endl;
    //pthread_join(pthread, NULL);
    return 0;
}

ulimit -s 21504 (也就是21M) , 把默认的stack size设置为21M

sundh@linux:~$ ulimit -s 21504
sundh@linux:~$ g++ -g -o test2 test2.cpp -lpthread
sundh@linux:~$ ./test2
This is a testenter func
enter func

可以成功运行, 验证了我们的猜想。

ulimit -s 修改 stack size, 也可以通过 pthread_attr_setstacksize() 来修改。 使用ulimit的一个后果就是它会影响到同一环境(同一shell或者终端)下后续启动的所有程序,如果修改成启动时设置的话就会影响到整个系统。 所以大部分情况下还是使用pthread_attr_setstacksize()

代码如下:

#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

struct thread_info {    /* Used as argument to thread_start() */
    pthread_t thread_id;        /* ID returned by pthread_create() */
    int       thread_num;       /* Application-defined thread # */
    char     *argv_string;      /* From command-line argument */
};

/* Thread start function: display address near top of our stack,
   and return upper-cased copy of argv_string */

static void *
thread_start(void *arg)
{
    struct thread_info *tinfo = arg;
    char *uargv, *p;

     <span style="color:#FF0000;">int a[1024*1024*5] = {0};</span>
 printf("Thread %d: top of stack near %p; argv_string=%s\n",
            tinfo->thread_num, &p, tinfo->argv_string);

   uargv = strdup(tinfo->argv_string);
    if (uargv == NULL)
        handle_error("strdup");

   for (p = uargv; *p != '\0'; p++)
        *p = toupper(*p);

   return uargv;
}

int
main(int argc, char *argv[])
{
    int s, tnum, opt, num_threads;
    struct thread_info *tinfo;
    pthread_attr_t attr;
    int stack_size;
    void *res;

   /* The "-s" option specifies a stack size for our threads */

   stack_size = -1;
    while ((opt = getopt(argc, argv, "s:")) != -1) {
        switch (opt) {
        case 's':
            stack_size = strtoul(optarg, NULL, 0);
            break;

       default:
            fprintf(stderr, "Usage: %s [-s stack-size] arg...\n",
                    argv[0]);
            exit(EXIT_FAILURE);
        }
    }

   num_threads = argc - optind;

   /* Initialize thread creation attributes */

   s = pthread_attr_init(&attr);
    if (s != 0)
        handle_error_en(s, "pthread_attr_init");

   if (stack_size > 0) {
        s = <span style="color:#FF0000;">pthread_attr_setstacksize</span>(&attr, stack_size);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setstacksize");
    }

   /* Allocate memory for pthread_create() arguments */

   tinfo = calloc(num_threads, sizeof(struct thread_info));
    if (tinfo == NULL)
        handle_error("calloc");

   /* Create one thread for each command-line argument */

   for (tnum = 0; tnum < num_threads; tnum++) {
        tinfo[tnum].thread_num = tnum + 1;
        tinfo[tnum].argv_string = argv[optind + tnum];

       /* The pthread_create() call stores the thread ID into
           corresponding element of tinfo[] */

       s = pthread_create(&tinfo[tnum].thread_id, &attr,
                           &thread_start, &tinfo[tnum]);
        if (s != 0)
            handle_error_en(s, "pthread_create");
    }

   /* Destroy the thread attributes object, since it is no
       longer needed */

   s = pthread_attr_destroy(&attr);
    if (s != 0)
        handle_error_en(s, "pthread_attr_destroy");

   /* Now join with each thread, and display its returned value */

   for (tnum = 0; tnum < num_threads; tnum++) {
        s = pthread_join(tinfo[tnum].thread_id, &res);
        if (s != 0)
            handle_error_en(s, "pthread_join");

       printf("Joined with thread %d; returned value was %s\n",
                tinfo[tnum].thread_num, (char *) res);
        free(res);      /* Free memory allocated by thread */
    }

   free(tinfo);
    exit(EXIT_SUCCESS);
}

$ ./a.out -s 0x1600000 hola salut servus   (0x1500000  == 20M,0x1600000==21M 

Thread 1: top of stack near 0xb7d723b8; argv_string=hola

Thread 2: top of stack near 0xb7c713b8; argv_string=salut

Thread 3: top of stack near 0xb7b703b8; argv_string=servus

Joined with thread 1; returned value was HOLA

Joined with thread 2; returned value was SALUT

Joined with thread 3; returned value was SERVUS

程序可以正常运行。 这里需要注意的一点是,主线程还是使用系统默认的stack size,也即8M, 不能在main() 里面声明超过2M的局部变量,创建子线程的时候调用了pthread_attr_setstacksize(), 修改stack size为21M,然后就能在子线程中声明5M的局部变量了。


版权声明:本文为博主原创文章,未经博主允许不得转载。

关于mysql thread_cache_size的设置优化!

首先解释下thread_cache_size的含义及相关参数。 thread
  • phf0313
  • phf0313
  • 2014年11月07日 09:41
  • 3622

MySQL thread_cache_size参数

发现 thread_cache_size 原来设置好小,这个默认值实质上也偏小,建议大的web项目,要调大这个值。 一、多大算合适 : 说实话我也不是很清楚,但是查阅了N多中文,英文资料,大部分: ...
  • m18580239676
  • m18580239676
  • 2015年09月11日 09:25
  • 298

mysql优化之thread_cache_size

mysql之thread_cache优化
  • hll814
  • hll814
  • 2016年02月29日 12:37
  • 5490

MYSQL优化之优化参数thread_cache_size

http://ceo.xwschool.net/blog/blog?do-showone-tid-176.html 以下是某门户网站的mysql状态实例及分析过程,绝对的第一手数据资料,很生动的体现...
  • wakin002
  • wakin002
  • 2013年01月25日 16:03
  • 519

mysql -参数thread_cache_size优化

以下是某门户网站的mysql状态实例及分析过程,绝对的第一手数据资料,很生动的体现了参数thread_cache_size优化的效果及优化该参数的必要性,希望对各位系统管理员能有帮助。 说明:   ...
  • huangchao064
  • huangchao064
  • 2016年06月14日 18:17
  • 425

进程栈大小 与 线程栈大小

我在FC3,gcc3.4.2环境下进行该实验,证明线程的栈确实有固定大小,也就是ulimit -a显示的那个值,在我的实验室环境下为10M字节  实验1:  #include   #includ...
  • xhhjin
  • xhhjin
  • 2012年05月18日 10:17
  • 7465

MySQL5.6版本性能调优my.cnf详解

[client] port = 3306 socket = /tmp/mysql.sock [mysqld] port = 3306 socket = /tmp/mysql.sock basedi...
  • qq_22929803
  • qq_22929803
  • 2016年04月25日 00:19
  • 7986

Tomcat能够稳定支持的最大用户并发数

Tomcat能够稳定支持的最大用户并发数
  • hll814
  • hll814
  • 2016年03月20日 11:30
  • 35685

linux多线程默认栈大小和最大线程数

linux的线程栈大小可以使用ulimit -s查看,对于ubunt 2.6的内核线程栈的默认大小为8M,如下: shine@shine-bupt:~/Program/C$ ulimit -s 8...
  • pingnanlee
  • pingnanlee
  • 2012年12月20日 23:21
  • 14686

线程堆栈大小的使用介绍

先来讲说线程内存相关的东西,主要有下面几条: 进程中的所有的线程共享相同的地址空间。任何声明为 static/extern 的变量或者堆变量可以被进程内所有的线程读写。一个线程真正拥有的...
  • u011784994
  • u011784994
  • 2017年02月18日 19:03
  • 1702
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:thread线程栈size及局部变量最大可分配size
举报原因:
原因补充:

(最多只允许输入30个字)