线程的堆栈

每当创建一个线程的时候,系统会为线程的堆栈保留一个栈区的空间区域,并将一些物理存储器提交给这个已保留的区域,我查看了VS2015,该默认设置大小是1MB。

它可以自己设置,在 项目-->属性-->链接器-->系统--->堆栈保留大小 这个地方填写自己希望的栈大小。

// 堆保留大小 1M    堆提交大小 4KB
// 栈保留大小 1M    栈提交大小 4KB

在页面大小是4KB的计算机上创建一个堆栈区域,其物理存储均具有页面保护属性,即PAGE_READWRITE。

线程访问时,从栈顶到栈底,页面状态不断变为已提交的页面,但是最底下的页面总是被保留的,从来不会被提交,这样做的目的是为了防止不小心改写进程所需要的其他数据。因为如果栈底下方的地址上,另一个地址空间区域已经提交了物理存储器,那么就有可能改写了其他数据,这是非常危险又隐蔽的错误。
结合SEH异常处理机制,可以写一个简单的求和函数,用递归的方法,让它发生栈溢出,并对异常进行捕获。

#include "stdafx.h"
#include <windows.h>

// 堆保留大小 1M 堆提交大小 4KB
// 栈保留大小 1M 栈提交大小 4KB

UINT Sum(UINT uNum);
LONG WINAPI FilterFunc(DWORD dwExceptionCode);
DWORD WINAPI SumThreadFunc(PVOID Param);

int main()
{

DWORD ThreadId;

UINT uSum = 5000; //大概可以计算4700以内的数

HANDLE ThreadHandle = CreateThread(NULL, 0,
SumThreadFunc, (PVOID)(UINT_PTR)uSum, 0, &ThreadId);

WaitForSingleObject(ThreadHandle, INFINITE);

GetExitCodeThread(ThreadHandle, (PDWORD)&uSum);
CloseHandle(ThreadHandle);

if (uSum == UINT_MAX)
{

printf("The number is too big, please enter a smaller number\r\n");
}
else
{
printf("%d\r\n", uSum);
}
return 0;
}

UINT Sum(UINT uNum)
{

return((uNum == 0) ? 0 : (uNum + Sum(uNum - 1)));
}

LONG WINAPI FilterFunc(DWORD dwExceptionCode)
{

return((dwExceptionCode == STATUS_STACK_OVERFLOW)
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH);
}

DWORD WINAPI SumThreadFunc(PVOID Param)
{
UINT uSumNum = PtrToUlong(Param);  //指针转ULONG
UINT uSum = UINT_MAX; // 错误数字

__try
{

uSum = Sum(uSumNum);  //递归求和
}
__except (FilterFunc(GetExceptionCode())) //如果是EXCEPTION_EXECUTE_HANDLER  (1)
{
// 说明堆栈溢出
// 添加一些自己的处理
printf("堆栈溢出了\r\n");
}

return uSum;
}

创建独立线程的理由:
1.每个线程保证拥有自己的1MB堆栈空间,而不是和他人分享1MB

2.当发生溢出时,每个线程只得到一次通知

3.系统自动收回提交给堆栈的物理存储器。

时间: 2024-08-11 04:53:58

线程的堆栈的相关文章

使用线程执行堆栈StackTraceElement设计Android日志模块

假设你想在你的Android自己主动打印程序MainActivity.onCreate(line:37)这样的类名.方法名称(行)登录如何实现? 1.介绍Java线程执行堆栈 Java.lang包中提供了StackTraceElement,能够用来获取方法的调用栈信息. 通过调用线程函数Thread.currentThread().getStackTrace()能够获得StackTraceElement[]的堆栈数组.数组中保存了线程中的运行调用的方法.观察以下的代码: @Override pr

进程线程及堆栈关系的总结(转)

突然想到进程的栈和线程的栈,就顺便说一下,线程的栈被自动分配到进程的内存空间中 进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性.进程和线程的区别在于: 简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 线程的划分尺度小于进程,使得多线程程序的并发性高. 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率. 线程在执行过程中与进程还是有区别的.每个独立的线程有一个程序运行的入口.顺序执行序列和程序的出

线程堆栈大小的使用介绍

先来讲说线程内存相关的东西,主要有下面几条: 进程中的所有的线程共享相同的地址空间. 任何声明为 static/extern 的变量或者堆变量可以被进程内所有的线程读写. 一个线程真正拥有的唯一私有储存是处理器寄存器. 线程栈可以通过暴露栈地址的方式与其它线程进行共享. 有大数据量处理的应用中,有时我们有必要在栈空间分配一个大的内存块或者要分配很多小的内存块,但是线程的栈空间的最大值在线程创建的时候就已经定下来了,如果栈的大小超过个了个值,系统将访问未授权的内存块,毫无疑问,再来的肯定是一个段错

JVM:如何分析线程堆栈

英文原文:JVM: How to analyze Thread Dump 在这篇文章里我将教会你如何分析JVM的线程堆栈以及如何从堆栈信息中找出问题的根因.在我看来线程堆栈分析技术是Java EE产品支持工程师所必须掌握的一门技术.在线程堆栈中存储的信息,通常远超出你的想象,我们可以在工作中善加利用这些信息. 我的目标是分享我过去十几年来在线程分析中积累的知识和经验.这些知识和经验是在各种版本的JVM以及各厂商的JVM供应商的深入分析中获得的,在这个过程中我也总结出大量的通用问题模板. 那么,准

线程堆栈是如何增长的

我们知道每个线程初始堆栈的默认空间是1M, 我们可以在VC编译的Linker项里进行设置,该值会被编译进最终的PE可执行文件中.线程堆栈内存包括commit部分和reserver部分,我们上面说的1M实际上指reserve部分,系统为了节约内存,并不会把所有reserve的1M都提交物理内存(commit), 所以初始只是提交部分内存. 我们可以随便找一个程序,通过WinDbg进行验证:!address -f:stack BaseAddr EndAddr+1 RgnSize Type State

查找现网环境中最耗费CPU的Java线程,并定位堆栈信息

参考:JVM性能调优监控工具jps.jstack.jmap.jhat.jstat.hprof使用详解 下面通过一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps.top.printf.jstack.grep. 第一步 先找出Java进程ID,我部署在服务器上的Java应用名称为mrf-center [email protected]:/# ps -ef | grep mrf-center | grep -v grep root 21711 1 1 14:47

通过 Java 线程堆栈进行性能瓶颈分析

改善性能意味着用更少的资源做更多的事情.为了利用并发来提高系统性能,我们需要更有效的利用现有的处理器资源,这意味着我们期望使 CPU 尽可能出于忙碌状态(当然,并不是让 CPU 周期出于应付无用计算,而是让 CPU 做有用的事情而忙).如果程序受限于当前的 CPU 计算能力,那么我们通过增加更多的处理器或者通过集群就能提高总的性能.总的来说,性能提高,需要且仅需要解决当前的受限资源,当前受限资源可能是: CPU: 如果当前 CPU 已经能够接近 100% 的利用率,并且代码业务逻辑无法再简化,那

线程池的堆栈问题

前面的文章已经讲了线程池和线程池的内部实现,这篇文章来了解线程池出错的堆栈信息的打印,毕竟异常堆栈信息的重要性对于程序员来说就像是指南针对于茫茫大海上的船只一样,没有指南针船只只能更加艰难的寻找方向,没有异常堆栈信息,排查问题时,也就只能像大海捞针一样,慢慢琢磨了. 看下面的例子: 1 public class DivTask implements Runnable { 2 3 int a,b; 4 public DivTask(int a,int b){ 5 this.a = a; 6 thi

记5.28大促压测的性能优化&mdash;线程池相关问题

目录: 1.环境介绍 2.症状 3.诊断 4.结论 5.解决 6.对比java实现 废话就不多说了,本文分享下博主在5.28大促压测期间解决的一个性能问题,觉得这个还是比较有意思的,值得总结拿出来分享下. 博主所服务的部门是作为公共业务平台,公共业务平台支持上层所有业务系统(2C.UGC.直播等).平台中核心之一的就是订单域相关服务,下单服务.查单服务.支付回调服务,当然结算页暂时还是我们负责,结算页负责承上启下进行下单.结算.跳支付中心.每次业务方进行大促期间平台都要进行一次常规压测,做到心里