programing

C에서 사용 가능한 스택 크기 확인 중

css3 2023. 7. 4. 22:05

C에서 사용 가능한 스택 크기 확인 중

저는 GCC 3.4.5 (mingw-special vista3)에서 MinGW를 사용하고 있습니다.

제 C 애플리케이션은 스택을 많이 사용하기 때문에 스택이 얼마나 남아 있는지 프로그래밍으로 알 수 있는 방법이 없을까요?

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

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

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);
}

한 번 봐주세요.다음을 통해 동일한 정보를 가져올 수 있습니다.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가 얼마나 변경되었는지 확인할 수 있습니다.그러면 사용 중인 스택의 양이 표시됩니다.

이것은 제가 포기한 문제입니다.많은 해킹과 기도를 통해 주어진 기계에서 주어진 시간에 작동하는 해결책을 얻을 수 있습니다.하지만 일반적으로 이것을 할 수 있는 적절한 방법은 없는 것 같습니다.

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

이제 스택의 위치, 크기 및 현재 위치를 확인하고 스택이 증가하는 방향을 알 수 있다고 가정합니다.스택 오버플로 모드는 언제입니까?추정치(즉, 로컬 변수의 주소 또는 스택 포인터의 값)가 너무 낙관적일 수 있기 때문에 마지막에 가까이 가서는 안 됩니다. 스택 포인터 너머로 메모리를 주소 지정하는 경우가 많습니다.또한 스택에서 주어진 함수(및 호출하는 함수)에 필요한 공간이 얼마나 되는지에 대한 단서도 없습니다.그래서 당신은 마지막에 꽤 많은 공간을 남겨야 할 것입니다.

이 혼란에 빠지지 말고 아주 깊은 재귀를 피하라고 조언할 수 있을 뿐입니다.또한 스택 크기를 늘리고 싶을 수도 있습니다. Windows에서는 이 파일을 실행 파일로 컴파일해야 합니다.

이것은 Windows 플랫폼에만 도움이 될 수 있습니다.

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


typedefstruct _IMAGE_NT_HEADERS {DWORD 서명;IMAGE_FILE_HEADER 파일 헤더;
IMAGE_OPTION_HEADER32 옵션 헤더;
IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedefstruct _IMAGE_OPTION_HEADER {...스택 예약의 DWORD 크기;스택 커밋의 DWORD 크기;...}

이러한 값을 얻는 간단한 방법이 있습니다. GetModuleHandle(NULL)을 사용하면 모듈의 이미지베이스(핸들), IMAGE_NT_HEADERS 구조(imagebase+)를 찾는 데 도움이 되는 IMAGE_DOS_HEADER 구조를 찾을 수 있는 주소가 제공됩니다.IMAGE_DOS_HEADER.e_lfanew) -> IMAGE_NT_HEADERS 필드에는 SizeOfStackReserveSizeOfStackCommit 필드가 있습니다.

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

만약 당신이 이것을 시도해 보는 것을 고려한다면, 저에게 알려주시면 제가 당신을 도와드리겠습니다.특정 지점에서 사용되는 스택의 크기를 구하는 방법이 있습니다.

창:나는 커널32.dll의 버추얼쿼리 기능을 사용하기 전에 이것을 해본 적이 있습니다.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);
    }

BTW: 이 코드는 StackOverflow에서 제가 코드의 버그를 수정하려고 할 때 질문했던 다른 질문에서도 찾을 수 있습니다.산술 작업으로 인해 안전하지 않은 C#링크 설명을 여기에 입력하는 데 오버플로가 발생했습니다.

Raymond Chen (The Old New Thing)은 이러한 질문에 대해 좋은 대답을 했습니다.

굳이 묻는다면, 당신은 아마도 뭔가 잘못하고 있을 것입니다.

다음은 스택 할당에 대한 Win32 세부 정보입니다: MSDN.

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

정확히 뭘 하려는 겁니까?

Linux에서는 getrusage를 호출하여 반환된 구조체의 ru_isrss 멤버(통합 비공유 스택 크기)를 확인합니다.

MINGW 사이트와 해당 소스 위조 사이트의 패치 추적을 통해 2008년 5월에 getrusage를 중심으로 일부 패치가 수행되었으며 일반적으로 꽤 오랫동안 지원된 것으로 보입니다.MinGW에서 지원하는 일반 Linux 기능의 양과 관련하여 주의 사항을 주의 깊게 확인해야 합니다.

언급URL : https://stackoverflow.com/questions/53827/checking-available-stack-size-in-c