【问题标题】:Automatic deallocation on avr-gccavr-gcc 上的自动释放
【发布时间】:2012-08-25 06:02:14
【问题描述】:

对 8 位 AVR 微控制器进行编程我遇到了一种行为,即 显示在此代码上:

  class classA
  {
      public:
          classA(Display *d) : _d(d) { _d->println("classA()", 0); }
          ~classA() { _d->println("~classA()", 1); }
          uint8_t array[200];
          Display *_d;
  };
  void useClassA(classA *a)
  {
      a->array[3] = 5;
  }
  void SomeClass::start()
  {
      SYSTEM_DISPLAY_FREE_RAM();
      debugMethod();
      _ui->lcd().println("after debugMethod", 3);
      SYSTEM_WAIT_DEBUG_BUTTON();
      SYSTEM_DISPLAY_FREE_RAM();
  }
  void SomeClass::debugMethod()
  {
      _ui->lcd().println("entered debugMethod", 3);
      SYSTEM_WAIT_DEBUG_BUTTON();
      SYSTEM_DISPLAY_FREE_RAM();

      _ui->lcd().println("before while", 3);
      SYSTEM_WAIT_DEBUG_BUTTON();
      volatile uint8_t i = 1;
      while (i != 0) 
      {
          classA cA(&_ui->lcd());
          SYSTEM_DISPLAY_FREE_RAM();
          cA.array[199] = i--;
          useClassA(&cA);
      }
      _ui->lcd().println("after while", 3);
      SYSTEM_WAIT_DEBUG_BUTTON();
      SYSTEM_DISPLAY_FREE_RAM();
  }

SYSTEM_DISPLAY_FREE_RAM() 计算可用 RAM,如中所述 http://jeelabs.org/2011/05/22/atmega-memory-use/。 当执行到达 SomeClass::start() 我得到以下输出:

  Free Ram: 2677
  entered debugMethod
  Free Ram: 2458
  before while
  classA()
  Free Ram: 2458
  ~classA()
  after while
  Free Ram: 2458
  after debugMethod
  Free Ram: 2677

尽管 classA 对象是在 while 内部创建和销毁的,但 内存似乎是在debugMethod() 的请求下分配的,并且仍然存在 直到方法结束。我希望只在内部分配内存 同时,因此具有Free Ram: 2458 的单一打印。

对发生的事情有任何解释吗?

有没有办法强制分配在while 内部进行,而不需要 使用new关键字?

使用的编译器:avr-gcc (WinAVR 20100110) 4.3.3

【问题讨论】:

  • 你编译优化了吗?可能是编译器将堆栈分配移动到 debugMethod() 的开头作为优化。
  • @Antti:是的,我使用-O1 编译。我将使用-O0 进行测试。
  • @Antti:-O0 也会发生同样的行为,所以不是因为优化。

标签: c++ memory embedded avr-gcc


【解决方案1】:

通常,整个函数的堆栈帧是在函数开始时分配的。 你可以试试 gcc 参数--param min-pretend-dynamic-size=100 它将尝试为超过 100 字节的对象动态分配和释放堆栈 [1]。

gcc 可以使用-S 开关向您显示汇编代码,查看它以了解正在发生的事情,以及 --param min-pretend-dynamic-size 是否对您的平台有任何影响和功能。

在您的情况下,另一种解决方案是将 while() 循环的主体移动到一个新函数中,因为这会创建/销毁包含 classA 对象的堆栈帧。

[1] gcc 文档:

最小假装动态尺寸

强制任何以字节为单位的大小等于或大于的自动对象 比指定值动态分配,好像它们的大小 不知道编译时间。这使得它们的存储成为 在包含它们的块的末尾释放,减少总堆栈 如果使用大量堆栈的多个函数被内联到一个 单一功能。它不会对合适的对象产生任何影响 分配给寄存器(即足够小并且 没有他们的地址),也没有在分配的对象上 函数的最外层块。默认值为零,导致对象 大小在编译时已知在函数中分配存储 进入。

【讨论】:

  • param min-pretend-dynamic-size 的想法非常好,但不幸的是它在这个编译器上不被接受:|| avr-gcc -c -mmcu=atmega1281 -I。 -x c++ -g -DF_CPU=14745600UL -O1 -fshort-enums -Wall --param min-pretend-dynamic-size=100 -IV0x05 -IV0x05/include -Ilib -MMD -MP -MF .dep/ADC3.od ADC3 .cpp -o obj/Debug/ADC3.o || cc1plus.exe: 错误: 无效参数'min-pretend-dynamic-size'
  • 是的,该选项似乎仅在某些较旧的 gcc 版本中可用,我在 gcc 4.x 及更高版本中找不到类似的东西,尽管您可以尝试-fconserve-stack
  • 我试过了,编译器也拒绝了这个。检查g++ -Q -O1 --help=optimizers 显示行 `-fconserve-stack [disabled]` - -O2、-O3 和 -Os 的结果相同。如果您有更多想法,请告诉我。感谢您的帮助!
猜你喜欢
  • 2011-11-09
  • 1970-01-01
  • 2011-05-03
  • 1970-01-01
  • 2015-12-01
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多