avr gcc上的自动解除分配

Automatic deallocation on avr-gcc

本文关键字:解除分配 gcc avr      更新时间:2023-10-16

在编程一个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的sigle打印。

对发生的事情有什么解释吗?

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

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

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

gcc可以向您展示带有-S开关的汇编代码,查看它以了解到底发生了什么,以及--param-min-pusset动态大小是否对您的平台和函数有任何影响。

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

[1] gcc文档:

最小假装动态大小

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