mMontu
mMontu

Reputation: 9273

Automatic deallocation on avr-gcc

Programming a 8-bit AVR microcontroller I've came across a behavior that is shown on this code:

  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() calculates available RAM as described in http://jeelabs.org/2011/05/22/atmega-memory-use/. When execution reaches SomeClass::start() I got the following output:

  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

Despite classA object is created and destructed inside the while, the memory seems to be allocated at the begging of debugMethod(), and remains until the method ends. I expected memory to be allocated only inside of the while, thus having a sigle print with Free Ram: 2458.

Any explanations of what is going on?

Is there a way to force the allocation to happen inside the while, without using new keyword?

Compiler used: avr-gcc (WinAVR 20100110) 4.3.3

Upvotes: 2

Views: 311

Answers (1)

nos
nos

Reputation: 229108

Typically the stack frame for the whole function is allocated at the start of the function. You can try the gcc argument --param min-pretend-dynamic-size=100 which will try to dynamically allocate and deallocate stack for objects over 100 bytes [1].

gcc can show you the assembly code with the -S switch, look at that to see under the hood on what's going on, and whether the --param min-pretend-dynamic-size had any effect on your platform and function.

Another solution in your case would be to move the body of your while() loop into a new function, as that would create/destroy the stack frame containing the classA object.

[1] gcc docs:

min-pretend-dynamic-size

Force any automatic object whose size in bytes is equal to or greater than the specified value to be allocated dynamically, as if their size wasn't known to compile time. This enables their storage to be released at the end of the block containing them, reducing total stack usage if multiple functions with heavy stack use are inlined into a single function. It won't have any effect on objects that are suitable for allocation to registers (i.e., that are sufficiently small and that don't have their address taken), nor on objects allocated in the outermost block of a function. The default, zero, causes objects whose sizes are known at compile time to have storage allocated at function entry.

Upvotes: 4

Related Questions