什么是安全的最大堆栈大小或如何衡量堆栈的使用?

Ste*_*nas 9 delphi stack delphi-2010

我有一个带有多个工作线程的应用程序,每个核心一个.在现代的8核机器上,我有8个这样的线程.我的应用程序加载了很多插件,这些插件也有自己的工作线程.因为应用程序使用大块内存(照片,例如200 MB),我有内存碎片问题.问题是每个线程都分配了{$ MAXSTACKSIZE ...}的地址空间.它不使用物理内存,而是使用地址空间.我将MAXSTACKSIZE从1MB降低到128KB,似乎可行,但如果我接近极限,我现在不行.有没有可能测量真正使用多少堆栈?

opc*_*0de 12

使用它来计算为当前线程堆栈提交的内存量:

function CommittedStackSize: Cardinal;
asm
  mov eax,[fs:$4] // base of the stack, from the Thread Environment Block (TEB)
  mov edx,[fs:$8] // address of lowest committed stack page
                  // this gets lower as you use more stack
  sub eax,edx
end;
Run Code Online (Sandbox Code Playgroud)

我没有的另一个想法.

  • Opc0de,你能不能在那段代码中加上一些评论来解释它在做什么? (4认同)

Phi*_*hiS 8

为了完整起见,我CommittedStackSizeopc0de的答案中添加了一个函数版本,用于确定对x86 32位和64位版本的Windows都有效的堆栈使用量(opc0de的函数仅适用于Win32).

opc0de的函数从Window的线程信息块(TIB)查询堆栈基址的地址和最低的已提交堆栈库.x86和x64有两个不同之处:

  • FSWin32上的段寄存器指向TIB ,但是通过GSon Win64 指向(参见此处)
  • 结构中项目的绝对偏移量不同(主要是因为某些项目是指针,分别是Win32/64上的4个字节和8个字节)

另请注意,BASM代码存在细微差别,因为在x64上,abs需要使汇编程序使用与段寄存器的绝对偏移量.

因此,适用于Win32和Win64版本的版本如下所示:

{$IFDEF MSWINDOWS}
function CommittedStackSize: NativeUInt;
//NB: Win32 uses FS, Win64 uses GS as base for Thread Information Block.
asm
 {$IFDEF WIN32}
  mov eax, [fs:04h] // TIB: base of the stack
  mov edx, [fs:08h] // TIB: lowest committed stack page
  sub eax, edx      // compute difference in EAX (=Result)
 {$ENDIF}
 {$IFDEF WIN64}
  mov rax, abs [gs:08h] // TIB: base of the stack
  mov rdx, abs [gs:10h] // TIB: lowest committed stack page
  sub rax, rdx          // compute difference in RAX (=Result)
 {$ENDIF}
{$ENDIF}
end;
Run Code Online (Sandbox Code Playgroud)