임베디드 시스템에서 단일 어레이에 대량의 스택을 할당하는 데 단점이 있습니까?


12

일반적으로 일부 데이터가 전역, 정적 또는 스택에 있는지 여부를 결정하는 데 아무런 문제가 없습니다 (여기서는 동적 할당이 없으므로 힙 사용 없음). 나는 이것 과 같은 몇 가지 Q / A를 읽었 지만 시스템 메모리에 비해 엄청난 양의 데이터가 관련되어 있기 때문에 내 질문은 더 구체적입니다.

개선하려고하는 기존 코드 (디자인, 가능한 문제, 성능 등)를 만들고 있습니다. 이 코드는 4KB의 RAM 만있는 이전 8 비트 MCU에서 실행됩니다 . 이 코드에서는 거의 1KB ( 4KB RAM 시스템의 경우 1KB) 배열을 사용 합니다. 이 배열의 각 바이트가 사용되지만 문제는 아닙니다. 문제는이 배열이 선언 된 파일의 정적 배열이므로 수명주기는 프로그램과 동일합니다 (즉, 무한한 것으로 간주 될 수 있음).

그러나 코드를 읽은 후에는이 배열에 무한 수명주기가 필요하지 않다는 것을 알았습니다.이 절차는 완전히 절차적인 방식으로 작성 및 처리되었으므로 사용 된 함수에서만 선언 할 수 있어야합니다. 이런 식으로 스택에 저장되므로이 1KB의 RAM을 절약 할 수 있습니다.

이제 질문 : 이것이 좋은 생각입니까? 설계 관점에서 무한 / 전역 수명주기가 필요하지 않은 경우 스택에 속합니다. 그러나, 그것은 4KB 중 1KB 입니다. 이러한 RAM의 25 %를 할당하는 데 단점이 있습니까? (스택의 50 % 이상일 수 있음)

누군가 이런 종류의 상황에 대한 경험을 공유 할 수 있습니까, 아니면 누군가 가이 배열을 스택에 올려 놓지 않는 정당한 이유를 생각할 수 있습니까? 디자인에 대한 의견뿐만 아니라 기술적 단점을 찾고 있습니다.

내가 의식하고있는 유일한 것은이 기능을 시작할 때 실제로 1KB의 스택을 확보해야한다는 것입니다. 어쩌면 그것이 내가 돌봐야 할 전부일 수도 있고 아닐 수도 있습니다.


4
"이 1KB의 RAM을 저장하십시오"라고 썼습니다. 무엇을 위해 저장 하시겠습니까? 어레이에 필요할 때 1KB를 사용할 수 있어야하므로 정적 할당을하지 않는 이유는 무엇입니까? 어레이에 필요하지 않은 메모리를 다시 사용합니까?
kkrambo

@kkrambo 어떤 시점에서 우리는 정적이든 스택이든 RAM에 더 이상 아무것도 추가 할 수 없을 때 시스템이 가득 찬 것으로 간주합니다. 이 배열을 사용할 때만이 배열을 스택에두면 동시에 사용되지 않는 한 다른 기능을 배치하게됩니다. 그러나 문제는 완전히 합법적입니다. 현재 SW에서 아무것도 변경하지 않으면 더 많은 RAM이 필요하지 않습니다.)
Tim

1
이 배열에 항상 같은 내용이 있거나 배열을 사용하는 함수가 호출 될 때 변경되는 내용이 있는지 확인할 수 있습니까?
Blrfl

@Blrfl 함수가 호출 될 때마다 변경됩니다.
Tim

답변:


8

내가 의식하고있는 유일한 것은이 기능을 시작할 때 실제로 1KB의 스택을 확보해야한다는 것입니다.

그렇습니다. 그것은 강력한 제약입니다. 스택에 사용 가능한 큰 공간을 확보하는 것보다 정적으로 확신하는 것이 좋습니다. 코드가 작 으면 최근 GCC 를 사용하여 코드를 컴파일하는 경우이 내용을 참조 하십시오 .

BTW에서 일부 저렴한 마이크로 프로세서는 "일반"프레임보다 "대형"호출 프레임을 더 많이 사용할 수 있습니다 (예 : 명령 세트가 스택 포인터에서 1 바이트 오프셋을 선호하기 때문에). YMMV.

또한 C로 코딩하고 큰 배열의 공간을 다른 목적으로 재사용 할 수 있다고 생각되면 전역 union유형 의 전역 변수가있는 공용체 멤버로 만드는 것을 고려할 수 있습니다 . 그렇습니다.

또는 응용 프로그램에 적합한 기본 힙 할당자를 코딩하는 것을 고려할 수 있습니다 ( malloc& free... 와 다른 API를 가질 수 있음 ).


1
고맙습니다. 실제로 이런 종류의 대답을 기대했습니다. 즉, 스택 오버플로로 끝나지 않도록 정적으로 할당하십시오. 불행히도 최근 GCC 컴파일러가 없으며 코드가 작지 않습니다.
Tim

플랫폼의 GCC 컴파일러를 소스 코드에서 컴파일하여 얻을 수 없습니까?
Basile Starynkevitch

2
나는 이미 하나를 가지고 있으며, 그것은 정말 오래되었습니다. 새로운 일을하는 것은 제 범위에 있지 않으며 제 스케줄에도 맞지 않습니다. 그러나 최신 도구를 사용하면 어떤 것이 더 쉬울 것입니다.
Tim

3
새로운 GCC를 약간 더 잘 최적화 할 수 있기 때문에 상사에게 최신 바이너리 도구를 제공하도록 요청하는 경우 (최신 바이너리 도구를 제공하거나 GCC를 재 컴파일 할 시간을 제공하여) IMHO는 가치가 있습니다 gcc -flto -Os. ) 그리고 당신은 약간의 기억을 얻을 수 있습니다 ....
Basile Starynkevitch

2
그것은 궤도에 있지만 한참 전에 오지 않을 것입니다. 최신 툴체인이있는 다른 시스템에서는 이미 -O를 사용하고 있지만이 -flto 매개 변수는 알지 못합니다. (GCC 5.4.1에서 몇 주 전에 GCC -Os 및 -O1-3 매개 변수를 사용하여 몇 가지 테스트를 수행했으며 RAM은 항상 동일하지만 FLASH와 MCU 실행 시간은 다릅니다. 그것은이 Q / A에서 언급 한 것과 같은 MCU에 없었습니다)
Tim

6

사람들은 RAM이 거꾸로 커지고 변수 값을 덮어 쓰기 때문에 설명 할 수없는 동작이 발생하기 때문에 큰 스택에주의하는 경향이 있습니다. 가능한 가장 낮은 스택 포인터 주소를 알고 루틴에 들어갈 때 할당 할 크기를 빼야하기 때문에 더 나빠집니다.

이는 이러한 종류의 분석 기능이있는 하드웨어 메모리 관리 (스택 오버플로 발생시 트랩 또는 결함을 생성해야 함) 또는 컴파일러에 대한 모든 작업입니다.

그렇지 않으면 RAM으로 원하는 것을 할 수 있습니다.


4

이전 답변에서 지적했듯이 메모리에 맞는 경우 배열을 정적 상태로 두는 것이 좋습니다. 항상 사용하지 않는 변수에 대해 메모리를 "폐기"한다는 의미가 있더라도 결정적인 메모리 풋 프린트를 갖는 것이 훨씬 더 중요합니다. 스택에 큰 어레이를 배치하면 스택이 너무 쉽게 터질 수 있으며 스택 오버플로는 찾기가 어렵고 재현하기 어려운 문제를 일으키는 경향이 있습니다 (스택을 보호하기 위해 MMU를 사용할 수없는 경우).

유니언이있는 다른 데이터와 블록을 공유하라는 제안은 IMO 유효하지만 잘못된 변수를 찾을 경우 찾기 어려운 문제의 원인이 될 수도 있습니다.

메모리가 부족하고 공유하기 위해 더 짧은 수명의 변수를 필사적으로 만들어야하는 경우 배열을 스택으로 이동하기 전에 자체 단점이 있지만 동적 메모리 할당을 추가하는 것이 좋습니다. 이 경우 어레이가 사용 가능한 메모리에 비해 상당히 큰 소리로 들리므로 답이 아닐 수도 있습니다.


1

플래시 저장 장치가있는 경우 다른 옵션이 있습니다. 데이터를 플래시에 저장하고 읽기 및 검색하여 램 액세스 속도를 상쇄 할 수 있습니다. 한 번에 하나의 레코드 만 램에로드하면됩니다. 레코드를 업데이트해야 할 경우 약간 더 복잡합니다. 세그먼트 화 된 마모 수준 메커니즘이 필요합니다. 나는 과거에 이것을했고 액세스 속도를 높이기위한 색인을 포함시켰다.


1
나는 또한 과거에 이것을했지만 내 질문은 스택에 넣을 때 직면 할 수있는 문제에 관한 것이지, 실제로 우리가 부족할 때 RAM의 대안은 아닙니다. 어쨌든 대답 해 주셔서 감사합니다
Tim

1

임베디드 시스템 작업을 할 때 특히, 당신은 컴파일 시간에 일어날 가능한 실패 많이 원하는 어느 것도 실행시 실패 (좋은 우리는 ...하지만,이를 달성 할 수 있다면).

프로그램이 정적으로 할당 된 임의의 상태에서 필요할 수있는 큰 배열을 만들면 정확히 그렇게됩니다.-링커는 결국 "이것은 RAM에 맞지 않습니다"라고 경고하지만 스택 할당은 단순히 디버그하기 어려운 스택으로 프로그램 충돌을 일으 킵니다. 오버플로.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.