设置线程堆栈大小

每个线程都有一个堆栈那么,这个堆栈多大呢?

HANDLE CreateThread(
       LPSECURITY_ATTRIBUTES lpThreadAttributes,
       SIZE_T dwStackSize,
       LPTHREAD_START_ROUTINE lpStartAddress,
       LPVOID lpParameter,
       DWORD dwCreationFlags,
       LPDWORD lpThreadId
);

在创建线程的时候可以指定堆栈大 小,dwStackSize=0则使用默认大小


-那默认大小又是多少?

      写个小程序算一下~

#include <stdio.h>
#include <windows.h>

#define STACK_SIZE 0.5*1024*1024

DWORD WINAPI ThreadFunc(PVOID pvParam)
{
      DWORD dwRet = 0;
      printf("%-3d:0x%x\n",pvParam,&dwRet);
      return dwRet;
}

int
main(int,char**)
{
      DWORD dwTid;
      printf("Main:0x%x\n",&dwTid);
      for(int i=0;i<50;i++)
        CreateThread(NULL,STACK_SIZE,ThreadFunc,(PVOID)i,0,&dwTid); // 莫小注:原作者这处代码有错,这不能修改线程栈大小

      Sleep(2000);
    return 0;
}

输出:

Main:0x12ff78
0       :0x50ffb0
1       :0x60ffb0
2       :0x70ffb0
3       :0x80ffb0
4       :0x90ffb0

0x60ffb0 - 0x50ffb0 = 0x100000 byte = 1MB

那么这个小程序中线程最小堆栈大小为1MB. (对么?为什么呢?后面有验证)
将STACK_SIZE换成0, 结果和上面一样
将STACK_SIZE换成2, 结果变成2MB

以下是从MSDN中查到的

Generally, the reserve size is the default reserve size specified in the executable header. However, if the initially committed size specified by dwStackSize is larger than the default reserve size, the reserve size is this new commit size rounded up to the nearest multiple of 1 MB.

根据winnt.h中的      IMAGE_OPTIONAL_HEADER结构体
typedef struct _IMAGE_OPTIONAL_HEADER {
       //
        // Standard fields.
        //

        WORD        Magic;
        BYTE        MajorLinkerVersion;
        BYTE        MinorLinkerVersion;
        DWORD       SizeOfCode;
        DWORD       SizeOfInitializedData;
        DWORD       SizeOfUninitializedData;
        DWORD       AddressOfEntryPoint;
        DWORD       BaseOfCode;
        DWORD       BaseOfData;

        //
        // NT additional fields.
        //

        DWORD       ImageBase;
        DWORD       SectionAlignment;
        DWORD       FileAlignment;
        WORD        MajorOperatingSystemVersion;
        WORD        MinorOperatingSystemVersion;
        WORD        MajorImageVersion;
        WORD        MinorImageVersion;
        WORD        MajorSubsystemVersion;
        WORD        MinorSubsystemVersion;
        DWORD       Win32VersionValue;
        DWORD       SizeOfImage;
        DWORD       SizeOfHeaders;
        DWORD       CheckSum;
        WORD        Subsystem;
        WORD        DllCharacteristics;
        DWORD       SizeOfStackReserve;
        DWORD       SizeOfStackCommit;
        DWORD       SizeOfHeapReserve;
        DWORD       SizeOfHeapCommit;
        DWORD       LoaderFlags;
        DWORD       NumberOfRvaAndSizes;
        IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

我推测,应该可以在链接期间指定栈大小
查看link.exe的参数

/STACK:reserve[,commit]
果然如此~~

看到网上有人问如何改变默认的线程堆栈大小,在MSDN中有答案:

The default size for the reserved and initially committed stack memory is specified in the executable file header. Thread or fiber creation fails if there is not enough memory to reserve or commit the number of bytes requested. To specify a different default stack size for all threads and fibers, use the STACKSIZE statement in the module definition (.def) file. For more information on these default sizes and how to change them, see the documentation included with your linker.

(模块定义 (.def) 文件为链接器提供有关被链接程序的导出、属性及其他方面的信息)

可见,默认线程堆栈大小在链接阶段可以由程序员指定

 

 

以上部分载自他人空间.

MSDN中有段话很重要:

To change the reserved stack size, set the dwCreationFlags parameter of CreateThread or CreateRemoteThread to STACK_SIZE_PARAM_IS_A_RESERVATION and use the dwStackSize parameter. 

我用MSDN2001版查看的时候,它有注明STACK_SIZE_PARAM_IS_A_RESERVATION 适用于XP系统, 在MSDN2008版没注明了,我是在XP下测试的

下面是我改的测试代码:

 

代码
 1 #include "stdafx.h"
 2 #include <stdio.h>
 3 #include <windows.h>
 4 
 5 #define STACK_SIZE 64*1024 // 设置线程栈为64K
 6 
 7 DWORD WINAPI ThreadFunc(PVOID pvParam)
 8 {
 9     DWORD dwRet = 0;
10     printf("%-3d:0x%x\n",pvParam,&dwRet);
11     Sleep(2000);  // 避免线程退出,这个线程栈地址又被分配给其它新创建的线程
12     return dwRet;
13 }
14 
15 int main(int,char**)
16 {
17     DWORD dwTid;
18     printf("Main:0x%x\n",&dwTid);
19 
20     HANDLE handles[10];
21 
22     for(int i=0;i<10;i++)
23     {
24         handles[i] = CreateThread(NULL,STACK_SIZE,ThreadFunc,(PVOID)i,STACK_SIZE_PARAM_IS_A_RESERVATION ,&dwTid);
25         Sleep(100); // 保证每次Create后得到的线程栈地址是递增的
26     }
27     for(int i=0; i<10; i++)
28     {
29         CloseHandle(handles[i]);
30     }
31 
32     getchar();
33     return 0;
34 }

   -----CreateThread(NULL,STACK_SIZE,ThreadFunc,(PVOID)i,STACK_SIZE_PARAM_IS_A_RESERVATION ,&dwTid);

运行结果:

 

 每次相差(10000)x = (655366)d = 64*1024, 设置成功,64K.

另外, Linux平台的栈默认大小应该是8192KB, Windows平台的栈默认大小应该是1024KB, 项目移植的时候要注意设置, 免得空间不足, 分配失败

posted @ 2010-08-06 23:45  莫小  阅读(27131)  评论(0编辑  收藏  举报