我使用的是MinGW和GCC 3.4.5(mingw-special vista r3)。我的C应用程序使用了大量的堆栈,所以我想知道是否有任何方法可以直观地告诉我还有多少堆栈,这样我就可以干净地处理这种情况,如果我发现我即将用完。如果没有,你会用什么其他方法来解决可能耗尽堆栈空间的问题?我不知道什么样的堆栈大小,我会开始,所以需要确定,也是图解。
tkqqtvp11#
getrusage函数获取当前的使用情况(参见man getrusage)。Linux中的getrlimit将有助于通过RLIMIT_STACK参数获取堆栈大小。
man getrusage
getrlimit
RLIMIT_STACK
#include <sys/resource.h> int main (void) { struct rlimit limit; getrlimit (RLIMIT_STACK, &limit); printf ("\nStack Limit = %ld and %ld max\n", limit.rlim_cur, limit.rlim_max); }
字符串请给予看一下man getrlimit。同样的信息可以通过ulimit -s或ulimit -a堆栈大小行来获取。也可以看看setrlimit函数,它允许设置限制。但是正如在其他答案中提到的,如果你需要调整堆栈,那么你可能应该重新考虑你的设计。如果你想要一个大数组,为什么不从堆中提取内存呢?
man getrlimit
ulimit -s
ulimit -a
setrlimit
iyr7buue2#
将局部变量的地址从堆栈中取出是可行的,然后在更嵌套的调用中,您可以减去另一个局部变量的地址,以找到它们之间的差异
size_t top_of_stack; void Main() { int x=0; top_of_stack = (size_t) &x; do_something_very_recursive(....) } size_t SizeOfStack() { int x=0; return top_of_stack - (size_t) &x; }
字符串如果你的代码是多线程的,那么你需要在每个线程的基础上存储top_of_stack变量。
jk9hmnmh3#
检查编译器是否支持stackavail()
djp7away4#
假设你知道整个堆栈的大小,你可能会添加一些汇编代码来读取ESP。如果你读取ESP并将其保存到main函数中,你可以将当前的ESP与main函数中的ESP进行比较,看看ESP改变了多少。这将给予你使用了多少堆栈的指示。
wd2eg0qa5#
这是一个我已经放弃的问题。通过大量的黑客攻击和(主要是)祈祷,你可以得到一个解决方案,在给定的时间在给定的机器上工作。但一般来说,似乎没有体面的方法来做到这一点。你必须从程序外部获取栈的位置和大小(在Linux上你可能从/proc/<pid>/maps获取)。在程序中你必须以某种方式测试你在栈中的位置。使用局部变量是可能的,但不能真实的保证它们实际上在栈中。你也可以尝试用一些程序集从栈指针寄存器获取值。所以现在你有了堆栈的位置,它的大小和当前位置,你假设你知道堆栈的增长方向。你什么时候进入堆栈溢出模式?你最好不要在接近结尾的时候这样做,因为你的估计(即局部变量的地址或来自堆栈指针的值)可能有点过于乐观;在堆栈指针之外寻址内存并不罕见。而且,你不知道任何给定的函数(以及它调用的函数)需要多少堆栈空间。所以你必须在最后留下相当多的空间。我只能建议你不要陷入这种混乱,尽量避免非常深的递归。你可能还想增加你的堆栈大小;在Windows上,你必须编译成可执行文件,我相信。
/proc/<pid>/maps
v1uwarro6#
这可能只对Windows平台有帮助:在PE头(IMAGE_NT_HEADERS)的exe有一些记录,如:
typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; typedef struct _IMAGE_OPTIONAL_HEADER { ... DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; ... }
字符串有一个简单的方法来获得这些值:使用GetModuleHandle(NULL)将给予你的模块的imagebase(handle),地址,你会发现一个IMAGE_DOS_HEADER结构,这将帮助你找到IMAGE_NT_HEADERS结构(imagebase+IMAGE_DOS_HEADER.e_lfanew)-> IMAGE_NT_HEADERS,在那里你会发现这些字段:SizeOfStackReserve和SizeOfStackCommit。操作系统将为您的堆栈分配的最大空间量是SizeOfStackReserve。如果你考虑尝试这个,让我知道,我会帮助你。有一种方法可以获得在某个点使用的堆栈大小。
u4dcyp6a7#
对于windows:我在使用Kernel32.dll中的VirtualQuery函数之前已经这样做了。我只有一个C#示例,但它演示了该技术:
public static class StackManagement { [StructLayout(LayoutKind.Sequential)] struct MEMORY_BASIC_INFORMATION { public UIntPtr BaseAddress; public UIntPtr AllocationBase; public uint AllocationProtect; public UIntPtr RegionSize; public uint State; public uint Protect; public uint Type; }; private const long STACK_RESERVED_SPACE = 4096 * 16; public unsafe static bool CheckForSufficientStack(UInt64 bytes) { MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION(); UIntPtr currentAddr = new UIntPtr(&stackInfo); VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION)); UInt64 stackBytesLeft = currentAddr.ToUInt64() - stackInfo.AllocationBase.ToUInt64(); return stackBytesLeft > (bytes + STACK_RESERVED_SPACE); } [DllImport("kernel32.dll")] private static extern int VirtualQuery(UIntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength); }
字符串顺便说一句:这段代码也可以在StackOverflow上找到,当我试图修复代码中的错误时,我问了另一个问题:Arithmetic operation resulted in an overflow in unsafe C#enter link description here
ny6fqffe8#
Raymond Chen(The Old New Thing)对这类问题有一个很好的回答:如果你非要问的话,你可能做错了什么。以下是Win32中有关堆栈分配的一些详细信息:MSDN。如果您认为可能会受到堆栈空间的限制,那么几乎肯定会受到可用虚拟内存的限制,在这种情况下,您需要找到不同的解决方案。你到底想干什么?
rqcrx0a69#
在Linux上,您可以调用getrusage并检查返回的struct rusage的ru_isrss成员(整数非共享堆栈大小)。从MinGW站点和它的SourceForge站点的补丁跟踪来看,我看到在2008年5月有一些关于getrusage的补丁,看起来它已经被广泛支持了一段时间。你应该仔细检查MinGW支持多少典型的Linux功能的任何警告。
getrusage
struct rusage
ru_isrss
9条答案
按热度按时间tkqqtvp11#
getrusage函数获取当前的使用情况(参见
man getrusage
)。Linux中的
getrlimit
将有助于通过RLIMIT_STACK
参数获取堆栈大小。字符串
请给予看一下
man getrlimit
。同样的信息可以通过ulimit -s
或ulimit -a
堆栈大小行来获取。也可以看看setrlimit
函数,它允许设置限制。但是正如在其他答案中提到的,如果你需要调整堆栈,那么你可能应该重新考虑你的设计。如果你想要一个大数组,为什么不从堆中提取内存呢?iyr7buue2#
将局部变量的地址从堆栈中取出是可行的,然后在更嵌套的调用中,您可以减去另一个局部变量的地址,以找到它们之间的差异
字符串
如果你的代码是多线程的,那么你需要在每个线程的基础上存储top_of_stack变量。
jk9hmnmh3#
检查编译器是否支持stackavail()
djp7away4#
假设你知道整个堆栈的大小,你可能会添加一些汇编代码来读取ESP。
如果你读取ESP并将其保存到main函数中,你可以将当前的ESP与main函数中的ESP进行比较,看看ESP改变了多少。这将给予你使用了多少堆栈的指示。
wd2eg0qa5#
这是一个我已经放弃的问题。通过大量的黑客攻击和(主要是)祈祷,你可以得到一个解决方案,在给定的时间在给定的机器上工作。但一般来说,似乎没有体面的方法来做到这一点。
你必须从程序外部获取栈的位置和大小(在Linux上你可能从
/proc/<pid>/maps
获取)。在程序中你必须以某种方式测试你在栈中的位置。使用局部变量是可能的,但不能真实的保证它们实际上在栈中。你也可以尝试用一些程序集从栈指针寄存器获取值。所以现在你有了堆栈的位置,它的大小和当前位置,你假设你知道堆栈的增长方向。你什么时候进入堆栈溢出模式?你最好不要在接近结尾的时候这样做,因为你的估计(即局部变量的地址或来自堆栈指针的值)可能有点过于乐观;在堆栈指针之外寻址内存并不罕见。而且,你不知道任何给定的函数(以及它调用的函数)需要多少堆栈空间。所以你必须在最后留下相当多的空间。
我只能建议你不要陷入这种混乱,尽量避免非常深的递归。你可能还想增加你的堆栈大小;在Windows上,你必须编译成可执行文件,我相信。
v1uwarro6#
这可能只对Windows平台有帮助:
在PE头(IMAGE_NT_HEADERS)的exe有一些记录,如:
字符串
有一个简单的方法来获得这些值:使用GetModuleHandle(NULL)将给予你的模块的imagebase(handle),地址,你会发现一个IMAGE_DOS_HEADER结构,这将帮助你找到IMAGE_NT_HEADERS结构(imagebase+IMAGE_DOS_HEADER.e_lfanew)-> IMAGE_NT_HEADERS,在那里你会发现这些字段:SizeOfStackReserve和SizeOfStackCommit。
操作系统将为您的堆栈分配的最大空间量是SizeOfStackReserve。
如果你考虑尝试这个,让我知道,我会帮助你。有一种方法可以获得在某个点使用的堆栈大小。
u4dcyp6a7#
对于windows:我在使用Kernel32.dll中的VirtualQuery函数之前已经这样做了。我只有一个C#示例,但它演示了该技术:
字符串
顺便说一句:这段代码也可以在StackOverflow上找到,当我试图修复代码中的错误时,我问了另一个问题:Arithmetic operation resulted in an overflow in unsafe C#enter link description here
ny6fqffe8#
Raymond Chen(The Old New Thing)对这类问题有一个很好的回答:
如果你非要问的话,你可能做错了什么。
以下是Win32中有关堆栈分配的一些详细信息:MSDN。
如果您认为可能会受到堆栈空间的限制,那么几乎肯定会受到可用虚拟内存的限制,在这种情况下,您需要找到不同的解决方案。
你到底想干什么?
rqcrx0a69#
在Linux上,您可以调用
getrusage
并检查返回的struct rusage
的ru_isrss
成员(整数非共享堆栈大小)。从MinGW站点和它的SourceForge站点的补丁跟踪来看,我看到在2008年5月有一些关于
getrusage
的补丁,看起来它已经被广泛支持了一段时间。你应该仔细检查MinGW支持多少典型的Linux功能的任何警告。