手动测试和修改多线程中栈空间大小。

2024-03-01 13:48

本文主要是介绍手动测试和修改多线程中栈空间大小。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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 toSTACK_SIZE_PARAM_IS_A_RESERVATION and use the dwStackSize parameter. 

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

下面是我改的测试代码:

代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 #include "stdafx.h"
#include <stdio.h>
#include <windows.h>#define STACK_SIZE 64*1024 // 设置线程栈为64KDWORD WINAPI ThreadFunc(PVOID pvParam)
{DWORD dwRet = 0;printf("%-3d:0x%x\n",pvParam,&dwRet);Sleep(2000);  // 避免线程退出,这个线程栈地址又被分配给其它新创建的线程return dwRet;
}int main(int,char**)
{DWORD dwTid;printf("Main:0x%x\n",&dwTid);HANDLE handles[10];for(int i=0;i<10;i++){handles[i] = CreateThread(NULL,STACK_SIZE,ThreadFunc,(PVOID)i,STACK_SIZE_PARAM_IS_A_RESERVATION ,&dwTid);Sleep(100); // 保证每次Create后得到的线程栈地址是递增的}for(int i=0; i<10; i++){CloseHandle(handles[i]);}getchar();return 0;
}

-----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, 项目移植的时候要注意设置, 免得空间不足, 分配失败




这篇关于手动测试和修改多线程中栈空间大小。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/762649

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

多线程解析报表

假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。 Way1 join import java.time.LocalTime;public class Main {public static void main(String[] args) thro

如何在运行时修改serialVersionUID

优质博文:IT-BLOG-CN 问题 我正在使用第三方库连接到外部系统,一切运行正常,但突然出现序列化错误 java.io.InvalidClassException: com.essbase.api.base.EssException; local class incompatible: stream classdesc serialVersionUID = 90314637791991

Java 多线程概述

多线程技术概述   1.线程与进程 进程:内存中运行的应用程序,每个进程都拥有一个独立的内存空间。线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换、并发执行,一个进程最少有一个线程,线程实际数是在进程基础之上的进一步划分,一个进程启动之后,进程之中的若干执行路径又可以划分成若干个线程 2.线程的调度 分时调度:所有线程轮流使用CPU的使用权,平均分配时间抢占式调度

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

JAVA- 多线程

一,多线程的概念 1.并行与并发 并行:多个任务在同一时刻在cpu 上同时执行并发:多个任务在同一时刻在cpu 上交替执行 2.进程与线程 进程:就是操作系统中正在运行的一个应用程序。所以进程也就是“正在进行的程序”。(Windows系统中,我们可以在任务管理器中看 到进程) 线程:是程序运行的基本执行单元。当操作系统执行一个程序时, 会在系统中建立一个进程,该进程必须至少建立一个线