Alex Allain , Ch 16 : Recursion, p.230의 C ++로 점프를 읽는 것과 똑같은 질문이 있었 으므로 테스트를 실행했습니다.
TLDR;
내 Arduino Nano (ATmega328 mcu)는 스택 오버플로가 발생하고 충돌하기 전에 211 회귀 함수 호출 (아래 주어진 코드에 대해)을 수행 할 수 있습니다.
먼저,이 주장을 해결하도록하겠습니다 :
때로는 재귀가 특정 알고리즘을 구현하는 유일한 빠른 옵션 인 경우가 있습니다.
[업데이트 : 아, 나는 "빠른"이라는 단어를 훑어 보았다. 이 경우 일부 유효성이 있습니다. 그럼에도 불구하고 다음과 같이 말할 가치가 있다고 생각합니다.]
아니요, 나는 이것이 진정한 진술이라고 생각하지 않습니다. 모든 알고리즘에 예외없이 재귀 및 비 재귀 솔루션이 모두 있다고 확신 합니다 . 때로는 훨씬 더 쉽습니다.재귀 알고리즘을 사용합니다. 그러나 마이크로 컨트롤러에서 사용하기 위해서는 재귀가 매우 어려워지고 안전에 중요한 코드에서는 절대 허용되지 않을 것입니다. 그럼에도 불구하고 물론 마이크로 컨트롤러에서 수행 할 수도 있습니다. 주어진 재귀 함수에 얼마나 "깊게"들어갈 수 있는지 테스트하려면 테스트하십시오! 실제 응용 프로그램에서 실제 테스트 사례로 실행하고 기본 조건을 제거하여 무한히 재귀합니다. 카운터를 인쇄하고 재귀 알고리즘이 RAM의 한계를 실제적으로 사용하기에 너무 가깝게 밀고 있는지 여부를 알 수 있도록 얼마나 "깊게"갈 수 있는지 직접 확인하십시오. 다음은 Arduino에서 스택 오버플로를 강제 실행하는 예입니다.
이제 몇 가지 메모 :
재귀 호출 수 또는 "스택 프레임"수는 다음과 같은 여러 가지 요소에 의해 결정됩니다.
- RAM 크기
- 스택에 이미 있거나 힙에 차지하는 양 (예 : 여유 RAM 문제;
free_RAM = total_RAM - stack_used - heap_used
또는 말할 수 있음 free_RAM = stack_size_allocated - stack_size_used
)
- 모든 새로운 재귀 함수 호출에 대해 스택에 배치 될 각각의 새로운 "스택 프레임"의 크기입니다. 이것은 호출되는 함수와 변수 및 메모리 요구 사항 등에 따라 다릅니다.
내 결과 :
- 20171106-2054hrs-16GB RAM의 Toshiba Satellite; 쿼드 코어, Windows 8.1 : 충돌 전 최종 값 인쇄 : 43166
- 20180306-1913 시간 Dell 고급 노트북 (64GB RAM 포함); 8 코어, Linux Ubuntu 14.04 LTS : 충돌 전에 최종 값이 인쇄 됨 : 261752
- 그 뒤에 문구
Segmentation fault (core dumped)
- ~ 4 ~ 5 초 정도 걸리고
- 20180306-1930hrs Arduino Nano : TBD는 ~ 250000이고 여전히 계산 중입니다. Arduino 최적화 설정으로 인해 재귀를 최적화해야합니다. 그렇습니다.
#pragma GCC optimize ("-O0")
파일 맨 위에 추가 하고 다시 실행하십시오.
- 20180307-0910hrs Arduino Nano : 32kB 플래시, 2kB SRAM, 16MHz 프로세스 또는 충돌 전 최종 값 인쇄 : 211
Here are the final print results:
209
210
211 ⸮ 9⸮ 3⸮
- 115200 직렬 전송 속도 (1/10 초)로 인쇄를 시작하면 1 초만에
- 2 kiB = 2048 bytes / 211 stack frames = 9.7 bytes / frame (모든 RAM이 스택에서 사용되고 있다고 가정하지만 실제로는 그렇지 않습니다)-그럼에도 불구하고 이것은 매우 합리적입니다.
코드:
PC 응용 프로그램 :
/*
stack_overflow
- a quick program to force a stack overflow in order to see how many stack frames in a small function can be loaded onto the stack before the overflow occurs
By Gabriel Staples
www.ElectricRCAircraftGuy.com
Written: 6 Nov 2017
Updated: 6 Nov 2017
References:
- Jumping into C++, by Alex Allain, pg. 230 - sample code here in the chapter on recursion
To compile and run:
Compile: g++ -Wall -std=c++11 stack_overflow_1.cpp -o stack_overflow_1
Run in Linux: ./stack_overflow_1
*/
#include <iostream>
void recurse(int count)
{
std::cout << count << "\n";
recurse(count + 1);
}
int main()
{
recurse(1);
}
아두 이노 "스케치"프로그램 :
/*
recursion_until_stack_overflow
- do a quick recursion test to see how many times I can make the call before the stack overflows
Gabriel Staples
Written: 6 Mar. 2018
Updated: 7 Mar. 2018
References:
- Jumping Into C++, by Alex Allain, Ch. 16: Recursion, p.230
*/
// Force the compiler to NOT optimize! Otherwise this recursive function below just gets optimized into a count++ type
// incrementer instead of doing actual recursion with new frames on the stack each time. This is required since we are
// trying to force stack overflow.
// - See here for all optimization levels: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
// - They include: -O1, -O2, -O3, -O0, -Os (Arduino's default I believe), -Ofast, & -Og.
// I mention `#pragma GCC optimize` in my article here: http://www.electricrcaircraftguy.com/2014/01/the-power-of-arduino.html
#pragma GCC optimize ("-O0")
void recurse(unsigned long count) // each call gets its own "count" variable in a new stack frame
{
// delay(1000);
Serial.println(count);
// It is not necessary to increment count since each function's variables are separate (so the count in each stack
// frame will be initialized one greater than the last count)
recurse (count + 1);
// GS: notice that there is no base condition; ie: this recursive function, once called, will never finish and return!
}
void setup()
{
Serial.begin(115200);
Serial.println(F("\nbegin"));
// First function call, so it starts at 1
recurse (1);
}
void loop()
{
}
참고 문헌 :
- Alex Allain의 C ++로 점프 , Ch 16 : 재귀, p.230
- http://www.electricrcaircraftguy.com/2014/01/the-power-of-arduino.html- 말 그대로 :이 "프로젝트"동안 내 웹 사이트를 참조하여 주어진 파일에 대해 Arduino 컴파일러 최적화 수준을 변경하는 방법을 상기시킵니다. 와
#pragma GCC optimize
내가 거기 문서화 알고 있었다 때문에 명령.