문제

저는 GCC 3.4.5(mingw-special vista r3)와 함께 MinGW를 사용하고 있습니다.

내 C 응용 프로그램은 많은 스택을 사용하므로 스택이 얼마나 남았는지 프로그래밍 방식으로 알려서 스택이 부족할 경우 상황을 깔끔하게 처리할 수 있는 방법이 있는지 궁금합니다.

그렇지 않다면 잠재적으로 스택 공간이 부족해지는 문제를 해결하는 다른 방법은 무엇입니까?

어떤 크기의 스택으로 시작할지 모르므로 프로그래밍 방식으로도 이를 식별해야 합니다.

도움이 되었습니까?

해결책

레이먼드 첸(오래된 새로운 것)는 이런 종류의 질문에 대한 좋은 대답을 가지고 있습니다.

물어봐야한다면 아마도 뭔가 잘못하고있을 것입니다.

스택 할당에 대한 Win32 세부 정보는 다음과 같습니다. MSDN.

스택 공간으로 인해 제한될 수 있다고 생각한다면 사용 가능한 가상 메모리로 인해 거의 확실히 제한될 것이며, 이 경우 다른 솔루션을 찾아야 합니다.

정확히 무엇을 하려는 건가요?

다른 팁

getrusage 함수는 현재 사용량을 알려줍니다.(보다 man getrusage).

그만큼 getrlimit Linux에서는 다음을 사용하여 스택 크기를 가져오는 데 도움이 됩니다. 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 한계를 설정할 수 있는 기능입니다.그러나 다른 답변에서 언급했듯이 스택을 조정해야 한다면 디자인을 다시 고려해야 할 것입니다.큰 배열을 원한다면 힙에서 메모리를 가져오는 것은 어떨까요?

스택에서 지역 변수의 주소를 가져오는 것이 작동합니다.그런 다음 더 중첩된 호출에서 다른 로컬 주소를 빼서 둘 사이의 차이점을 찾을 수 있습니다.

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 변수 저장을 처리해야 합니다.

컴파일러가 stackavail()을 지원하는지 확인하세요.

전체 스택의 크기를 알고 있다고 가정하면 ESP를 읽기 위해 일부 어셈블리 코드를 추가할 수 있습니다.
ESP를 읽고 메인 함수에 따로 저장하면 현재 ESP를 메인에 있는 ESP와 비교하여 ESP가 얼마나 변경되었는지 확인할 수 있습니다.그러면 얼마나 많은 스택이 사용되었는지 알 수 있습니다.

이건 제가 포기한 문제입니다.많은 해킹과 (주로) 기도를 통해 특정 머신에서 특정 시간에 작동하는 솔루션을 얻을 수 있습니다.그러나 일반적으로 이를 수행하는 적절한 방법은 없는 것 같습니다.

프로그램 외부에서 스택 위치와 크기를 얻어야 합니다(Linux에서는 다음에서 얻을 수 있습니다). /proc/<pid>/maps).프로그램에서 어떻게든 스택의 위치를 ​​테스트해야 합니다.지역 변수를 사용하는 것은 가능하지만 실제로 스택에 있다는 보장은 없습니다.일부 어셈블리를 사용하여 스택 포인터 레지스터에서 값을 가져오려고 시도할 수도 있습니다.

이제 스택의 위치, 크기 및 현재 위치를 알았으며 스택이 어느 방향으로 성장하는지 알고 있다고 가정합니다.언제 스택 오버플로 모드로 전환됩니까?당신의 추정(예:지역 변수의 주소 또는 스택 포인터의 값)은 아마도 너무 낙관적일 것입니다.스택 포인터 너머의 메모리 주소를 지정하는 것은 드문 일이 아닙니다.또한 특정 함수(및 호출하는 함수)가 스택에 얼마나 많은 공간을 필요로 하는지 전혀 알 수 없습니다.그래서 마지막에 꽤 많은 공간을 남겨두어야 합니다.

나는 이 혼란에 빠지지 말고 매우 깊은 재귀를 피하려고 노력하라고 조언할 뿐입니다.스택 크기를 늘리고 싶을 수도 있습니다.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에서도 찾을 수 있습니다. 안전하지 않은 C#에서 산술 연산으로 인해 오버플로가 발생했습니다.여기에 링크 설명을 입력하세요

아마도 이것은 Windows 플랫폼에만 도움이 될 것입니다.

exe의 PE 헤더(IMAGE_NT_HEADERS)에는 다음과 같은 레코드가 있습니다.

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)을 사용하면 모듈의 이미지 베이스(핸들)와 IMAGE_NT_HEADERS 구조(imagebase+IMAGE_DOS_HEADER.e_lfanew) -> IMAGE_NT_HEADERS를 찾는 데 도움이 되는 IMAGE_DOS_HEADER 구조를 찾을 수 있는 주소가 제공됩니다. 해당 필드를 찾을 것입니다: SizeOfStackReserve 그리고 SizeOfStack커밋.

OS가 스택에 할당하는 최대 공간은 SizeOfStackReserve입니다.

시도해 볼 것을 고려하고 계시다면 알려주시면 도와드리겠습니다.특정 지점에서 사용되는 스택의 크기를 구하는 방법이 있습니다.

Linux에서는 getrusage를 호출하고 반환 된 Struct Rusage의 Ru_isrss 회원 (적분하지 않은 스택 크기)을 확인합니다.

MINGW 사이트와 해당 sourceforge 사이트의 패치 추적을 통해 2008년 5월에 getrusage 관련 패치가 일부 이루어졌으며 꽤 오랫동안 일반적으로 지원되어 온 것으로 보입니다.MinGW에서 지원되는 일반적인 Linux 기능의 양과 관련된 주의 사항을 주의 깊게 확인해야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top