스택 크기 추정
다중 스레드 내장 소프트웨어(C 또는 C++로 작성됨)에서 스레드는 오버플로 없이 작업을 완료할 수 있도록 충분한 스택 공간을 제공해야 합니다.일부 실시간 임베디드 환경에서는 스택의 정확한 사이징이 매우 중요한데, 이는 (적어도 제가 작업한 일부 시스템에서는) 운영 체제가 이를 감지하지 못하기 때문입니다.
일반적으로 (주 스레드 이외의) 새 스레드에 대한 스택 크기는 스레드가 생성될 때(즉, pthread_create() 등의 인수에서) 지정됩니다.이러한 스택 크기는 코드가 처음 작성되거나 테스트될 때 양호한 것으로 알려진 값으로 하드 코딩되는 경우가 많습니다.
그러나 향후 코드 변경으로 인해 하드 코딩된 스택 크기의 기반이 되는 가정이 깨지는 경우가 많으며, 운명적인 어느 날 스레드가 호출 그래프의 더 깊은 분기 중 하나에 들어가 스택을 오버플로하여 전체 시스템이 다운되거나 메모리가 손상됩니다.
스레드에서 실행된 코드가 스택에서 구조 인스턴스를 선언하는 경우에 이 문제를 직접 본 적이 있습니다.구조물이 추가 데이터를 보유하도록 증강되면 스택 크기가 그에 따라 팽창하여 잠재적으로 스택 오버플로가 발생할 수 있습니다.이것은 구조에 필드를 추가하는 전체 효과를 즉시 알 수 없는 기존 코드베이스에 큰 문제가 될 수 있다고 생각합니다(구조가 사용되는 모든 장소를 찾기에는 너무 많은 스레드/함수).
"스택 사이징" 질문에 대한 일반적인 반응은 "그것들은 휴대용이 아닙니다"이므로, 컴파일러, 운영 체제 및 프로세서가 모두 이 조사를 위한 알려진 양이라고 가정해 보겠습니다.또한 재귀가 사용되지 않는다고 가정하고, 따라서 "무한 재귀" 시나리오의 가능성에 대해서는 다루지 않습니다.
스레드에 필요한 스택 크기를 추정할 수 있는 신뢰할 수 있는 방법은 무엇입니까?오프라인(정태분석)과 자동으로 가능한 방법을 원하지만, 모든 아이디어가 환영합니다.
런타임 평가
온라인 방식은 전체 스택을 0xAAAAA(또는 폭이 얼마든지 상관없이 0xAAA)와 같은 특정 값으로 도색하는 것입니다.그런 다음 그림의 어느 정도를 그대로 두었는지 확인함으로써 과거에 스택이 얼마나 크게 성장했는지 확인할 수 있습니다.
설명과 함께 설명을 보려면 이 링크를 보세요.
장점은 간단하다는 것입니다.단점은 테스트 중에 스택 크기가 사용된 스택의 양을 초과하지 않을 것이라는 점입니다.
정적 평가
정적인 체크가 있고 심지어 해킹된 gcc 버전도 있다고 생각합니다.제가 말씀드릴 수 있는 것은 일반적인 경우에는 정적 검사가 매우 어렵다는 것입니다.
또한 이 질문을 살펴봅니다.
대상이 요구 사항에 맞는 경우 Stack Analyzer와 같은 정적 분석 도구를 사용할 수 있습니다.
상당한 비용을 지출하고 싶다면 클록워크와 같은 상용 정적 분석 도구를 사용할 수 있습니다.비록 클로크워크가 주로 소프트웨어 결함과 보안 취약점을 탐지하는 것을 목표로 하지만 말입니다.그러나 작업 또는 스레드 내에서 스택 오버플로를 탐지하는 데 사용할 수 있는 'kwstack overflow'라는 도구도 있습니다.저는 제가 진행하는 임베디드 프로젝트에 사용하고 있으며, 긍정적인 결과를 얻었습니다.저는 이런 도구가 완벽하다고 생각하지는 않지만, 이 상업적 도구들은 매우 훌륭하다고 생각합니다.지금까지 접했던 대부분의 도구들은 함수 포인터에 어려움을 겪습니다.그린힐스와 같은 많은 컴파일러 공급업체들이 현재 자신들의 컴파일러에 비슷한 기능을 구축하고 있다는 것도 알고 있습니다.컴파일러는 스택 크기에 대한 정확한 결정을 내리는 데 필요한 모든 세부 사항에 대해 잘 알고 있기 때문에 이것이 아마도 가장 좋은 해결책이 될 것입니다.
시간이 있다면 스크립트 언어를 사용하여 자신만의 스택 오버플로 분석 도구를 만들 수 있을 것입니다.스크립트는 태스크 또는 스레드의 진입점을 식별하고 완전한 함수 호출 트리를 생성한 다음 각 함수가 사용하는 스택 공간의 양을 계산해야 합니다.저는 아마 사용 가능한 무료 도구가 있을 거라고 생각합니다. 그것은 완전한 함수 호출 트리를 생성할 수 있기 때문에 더 쉽게 만들 수 있을 것입니다.각 기능이 사용하는 스택 공간을 생성하는 플랫폼의 세부 사항을 알고 있다면 매우 쉬울 수 있습니다.예를 들어, PowerPC 기능의 첫 번째 조립 명령은 스택 포인터를 기능에 필요한 양만큼 조정하는 업데이트 명령과 함께 저장 단어인 경우가 많습니다.첫 번째 명령에서 바로 바이트 단위의 크기를 가져올 수 있으므로 사용되는 총 스택 공간을 비교적 쉽게 파악할 수 있습니다.
이러한 분석 유형은 모두 스택 사용에 대한 최악의 경우 상한의 근사치를 제공하며, 이는 정확히 알고 싶은 것입니다.물론 전문가들(제가 함께 일하는 전문가들)은 스택 공간을 너무 많이 할당하고 있다고 불평할 수 있지만, 그들은 좋은 소프트웨어 품질에 신경 쓰지 않는 공룡들입니다. :)
스택 사용량을 계산하지는 않지만 프로세서의 MMU(메모리 관리 장치)를 사용하여 스택 오버플로를 감지하는 것도 가능합니다.저는 파워 PC를 사용하여 VxWorks 5.4에서 이 작업을 수행했습니다.아이디어는 간단합니다. 쓰기 방지 메모리 페이지를 스택 맨 위에 올려놓기만 하면 됩니다.오버플로가 발생하면 프로세서 실행이 발생하고 스택 오버플로 문제를 빠르게 알 수 있습니다.물론 스택 크기를 얼마나 늘려야 하는지는 알 수 없지만 예외/코어 파일 디버깅을 잘 한다면 적어도 스택에 오버플로가 발생한 호출 순서를 파악할 수 있습니다.그런 다음 이 정보를 사용하여 스택 크기를 적절히 늘릴 수 있습니다.
-dj하우스
무료는 아니지만 Coverity는 스택의 정적 분석을 수행합니다.
정적(오프라인) 스택 검사는 보기만큼 어렵지 않습니다.내장 IDE(Rapidi)를 위해 구현했습니다.TTy) — 현재 ARM7(NXP LPC2xxx), Cortex-M3(STM32 및 NXP LPC17xx), x86 및 사내 MIPS ISA 호환 FPGA 소프트코어에서 작동합니다.
기본적으로 우리는 실행 가능한 코드의 간단한 구문 분석을 사용하여 각 함수의 스택 사용을 결정합니다.가장 중요한 스택 할당은 각 기능을 시작할 때 수행됩니다. 다양한 최적화 수준 및 해당되는 경우 ARM/Thumb 명령 세트 등에 따라 어떻게 변경되는지 확인하십시오.또한 작업에는 대개 자체 스택이 있으며 ISR은(항상은 아니지만) 별도의 스택 영역을 공유하는 경우가 많습니다!
각 함수의 사용법이 있으면 구문 분석에서 콜 트리를 구축하고 모든 함수의 최대 사용법을 계산하는 것이 매우 쉽습니다.우리의 IDE는 당신을 위한 스케쥴러(효과적인 씬 RTOS)를 생성하기 때문에 어떤 기능이 '태스크'로 지정되고 어떤 기능이 ISR인지 정확히 알 수 있으므로 각 스택 영역별로 최악의 사용 상황을 알 수 있습니다.
물론, 이 수치들은 거의 항상 실제 최대치를 초과합니다.다음과 같은 기능을 생각해 보십시오.sprintf많은 스택 공간을 사용할 수 있지만 제공하는 형식 문자열과 매개 변수에 따라 매우 다양합니다.시작할 때 알려진 값으로 스택을 채운 다음 디버거를 잠시 실행한 후 일시 중지하고 각 스택의 값이 여전히 얼마나 많은지 확인하는 동적 분석을 사용할 수도 있습니다(높은 워터마크 스타일 테스트).
두 가지 접근 방식 모두 완벽하지는 않지만, 두 가지를 모두 결합하면 실제 사용 방식이 어떨지에 대해 상당히 잘 알 수 있을 것입니다.
이 질문에 대한 답변에서 설명한 바와 같이, 일반적인 기법은 알려진 값으로 스택을 초기화한 다음 잠시 동안 코드를 실행하고 패턴이 어디서 멈추는지 확인하는 것입니다.
이것은 오프라인 방식이 아니라 제가 진행하고 있는 프로젝트에서 우리는 애플리케이션 내의 모든 작업 스택에 하이 워터 마크를 읽어내는 디버그 명령을 가지고 있습니다.각 작업에 대한 스택 사용량과 사용 가능한 헤드룸의 양을 표로 출력합니다.사용자 상호 작용이 많은 24시간 실행 후 이 데이터를 확인하면 정의된 스택 할당이 "안전하다"는 확신을 얻을 수 있습니다.
이것은 스택을 알려진 패턴으로 채우는 잘 시도된 기술을 사용하여 작동하며, 이것을 다시 쓸 수 있는 유일한 방법은 일반적인 스택 사용이라고 가정합니다. 그러나 다른 방법으로 스택 오버플로를 작성하는 경우에는 걱정할 필요가 없습니다.
우리는 제 직장에서 임베디드 시스템으로 이 문제를 해결하려고 했습니다.문제가 발생했습니다. 신뢰할 수 있는 답변을 얻기에는 코드(자체 프레임워크와 타사 프레임워크)가 너무 많습니다.다행히도 저희 장치는 리눅스 기반이었기 때문에 모든 스레드에 2mb를 제공하고 가상 메모리 관리자가 사용을 최적화하도록 하는 표준 동작으로 되돌아갔습니다.
의 한 는 3 툴 중였습니다.mlock전체 메모리 공간(성능 향상을 위한 ideally)에 저장할 수 있습니다.이로 인해 스레드의 각 스레드(그 중 75-150개)에 대한 스택 2mb가 모두 호출되었습니다.우리는 그것을 알아내고 불쾌감을 주는 대사를 언급할 때까지 우리의 메모리 공간의 절반을 잃었습니다.
참고: 리눅스의 가상 메모리 관리자(vmm)는 RAM을 4k 청크에 할당합니다.새 스레드가 스택에 사용할 2MB의 주소 공간을 요구하면 vmm은 최상위 페이지를 제외한 모든 페이지에 잘못된 메모리 페이지를 할당합니다.스택이 가짜 페이지로 커지면 커널은 페이지 오류를 감지하고 가짜 페이지를 실제 페이지와 스왑합니다(실제 RAM을 4k 더 사용).이렇게 하면 스레드의 스택이 필요한 크기(2mb 미만인 경우)로 증가할 수 있으며 vmm은 최소한의 메모리만 사용하도록 보장합니다.
이미 수행된 일부 제안과는 별개로 임베디드 시스템에서는 스택 크기를 합리적인 크기로 유지해야 하기 때문에 스택 사용량을 엄격하게 제어해야 하는 경우가 많습니다.
어떤 의미에서 스택 공간을 사용하는 것은 메모리를 할당하는 것과 비슷하지만, 스택 사용량을 제어하지 않기 위해 할당이 성공했는지 확인할 수 있는 쉬운 방법이 없는 경우 시스템이 다시 충돌하는 이유를 파악하기 위해 영원히 애를 쓰게 됩니다.예를 들어, 시스템에서 스택의 로컬 변수에 대한 메모리를 할당하는 경우 malloc()로 해당 메모리를 할당하거나 malloc()를 사용할 수 없는 경우 자신의 메모리 핸들러를 작성합니다(이것은 충분히 간단한 작업입니다).
아니오:
void func(myMassiveStruct_t par)
{
myMassiveStruct_t tmpVar;
}
예-예:
void func (myMassiveStruct_t *par)
{
myMassiveStruct_t *tmpVar;
tmpVar = (myMassiveStruct_t*) malloc (sizeof(myMassicveStruct_t));
}
꽤 분명해 보이지만 종종 그렇지 않습니다 - 특히 malloc()을 사용할 수 없을 때.
물론 여전히 문제가 있을 것이므로 이는 도움이 되는 것일 뿐 문제를 해결하지는 못합니다.그러나 스택에 적합한 크기를 발견한 후 몇 가지 코드 수정 후에 다시 스택 공간이 부족해지면 여러 버그나 다른 문제(한 개에는 너무 깊은 호출 스택)를 탐지할 수 있으므로 향후 스택 크기를 추정하는 데 도움이 될 것입니다.
100% 확실하진 않지만, 이것도 가능할 것 같습니다.jtag 포트가 노출된 경우 Trace32에 연결하여 최대 스택 사용량을 확인할 수 있습니다.이 경우 초기에 상당히 큰 임의 스택 크기를 지정해야 합니다.
언급URL : https://stackoverflow.com/questions/1756285/stack-size-estimation
'codememo' 카테고리의 다른 글
| 워드프레스, 깃 및 도커 (0) | 2023.10.10 |
|---|---|
| jdbc 연결에서 드라이버 클래스 이름(드라이버 이름 아님)을 가져오는 방법 (0) | 2023.10.10 |
| 비트 시프트와 정수 프로모션? (0) | 2023.10.10 |
| 로컬 IIS 7.5에서 Windows 인증이 작동하지 않습니다. 오류 401.1 (0) | 2023.10.10 |
| DOM에서 JavaScript 이동 요소 (0) | 2023.10.05 |