Page 1 of 1

Trap in MAU

Posted: Thu Dec 08, 2011 9:23 pm
by Helpdesk
What does "Trap @00001630H in MAU, Line: 26, Code: 11" mean?

Re: Trap in MAU

Posted: Thu Dec 08, 2011 9:30 pm
by cfbsoftware
The identification of the error codes are in Section 8.1 Runtime Error Codes in the Oberon for Microcontrollers document. Trap 11 is a heap overflow.

If you suspect you are not always going to have enough free memory on your MCU when using NEW to allocate heap space you should use the MAU functions HeapUsed or MemAvailable to keep track of your usage.

Re: Trap in MAU

Posted: Sun Dec 11, 2011 11:52 pm
by Ivan Denisov
Thanks! I have been solved my problem. The NEW() should not be called in WHILE TRUE DO ... END; loop to prevent heap overflow. It should be put in PROCEDURE to memory be cleaned right way! I tested this in V4.01 of Astrobe.

Right way (do not led to heap overflow):

Code: Select all

MODULE MauV4;
IMPORT Out, MAU, Main;

PROCEDURE Test;
  VAR p: ARRAY OF INTEGER;
BEGIN
    NEW(p, 4);
    Out.String("proc "); Out.Int(MAU.MemAvailable(), 6); Out.Ln; 
END Test;

PROCEDURE Run;
BEGIN
  WHILE MAU.MemAvailable() > 10 DO
    Out.String("while "); Out.Int(MAU.MemAvailable(), 6); Out.Ln;
    Test
  END;
END Run;

BEGIN
  Run
END MauV4.
Wrong way (led to heap overflow):

Code: Select all

MODULE MauV4;
IMPORT Out, MAU, Main;

PROCEDURE Run;
  VAR p: ARRAY OF INTEGER;
BEGIN
  WHILE MAU.MemAvailable() > 10 DO
    Out.String("free "); Out.Int(MAU.MemAvailable(), 6); Out.Ln;
    NEW(p, 4);
  END;
END Run;

BEGIN
  Run
END MauV4.
BUT am I understand right, that then NEW called previous ARRAY should be removed from the memory? why it is not removed? Is it a bug or the rule?

Re: Trap in MAU

Posted: Mon Dec 12, 2011 11:55 am
by cfbsoftware
NEW only ever allocates memory - it never frees any memory. When you use NEW on a local dynamic array as in your example the memory is allocated on the stack (not the heap), just like the memory used by other local variables. When you exit from the procedure the memory used by the dynamic array is returned to the system.

If you allocate an array more than once, e.g.

Code: Select all

NEW(p, 4);
NEW(p, 4);
it would not cause an error but is no more useful than declaring two arrays e.g.

Code: Select all

VAR
   a, b: ARRAY 4 OF INTEGER;
and never using one of them.

Note that as p is an ARRAY OF INTEGER in your example, NEW(p, 4) allocates enough memory for 4 INTEGERs, i.e. 16 bytes. If you really want to test that you have enough memory you should write:

Code: Select all

IF MAU.MemAvailable() >= 16 THEN 
  NEW(p, 4) 
END;

Re: Trap in MAU

Posted: Sat Sep 29, 2012 9:36 am
by Ivan Denisov
I can not understand how to free memory from new elements. I make the example to demonstrate the problem.

I made a chain of data structures received form PC, and then processing them one by one. But cant find the way how to free unused chain elements.

Help me please.

Code: Select all

MODULE MauV4;

  IMPORT Out, Main, MAU;
  
  TYPE
    Event = POINTER TO RECORD
      next: Event
    END;
  
  VAR
    v: Event;
    
  PROCEDURE Add;
    VAR item: Event;
  BEGIN
    IF v = NIL THEN
      NEW(v);
      v.next := NIL
    ELSE
      item := v;
      WHILE item.next # NIL DO
        item := item.next
      END;
      NEW(item.next);
      item.next.next := NIL
    END
  END Add;
  
  PROCEDURE Clear;
  BEGIN
    (* Do some work here *)
    (* How to free memory from a chain unused tail ??? *)
    
    v := NIL;
    v.next := NIL;
  END Clear;
  
  PROCEDURE Run;
  BEGIN
    v := NIL;
    v.next := NIL;
    
    WHILE TRUE DO
      Out.String("Available: "); Out.Int(MAU.MemAvailable(), 5); Out.Ln;
      Add;
      Clear
    END
  END Run;

BEGIN
  Run

END MauV4.
I had been test it on a Astrobe V3.4 Starter and Astrobe V4.0.2 Evolution.

Re: Trap in MAU

Posted: Sat Sep 29, 2012 12:44 pm
by cfbsoftware
Astrobe has a built-in function called DISPOSE which is complementary to NEW. You can use DISPOSE to possibly deallocate dynamic memory for subsequent reuse. This was mentioned in a previous post in this forum:

NEW / DISPOSE and Memory Allocation

Alternatively, if you have a situation where a list of pointers is continually growing and shrinking then you could implement a system which maintains a separate list of the freed pointers. Then, when you need to to use an additional pointer of the same type you can take it from the freed list. You would only need to use NEW to allocate another pointer when the freed list is empty. The total amount of memory used is then limited to the maximum number of pointers that are in use at any one time.

Re: Trap in MAU

Posted: Sat Sep 29, 2012 5:22 pm
by Ivan Denisov
Thanks for the answer and advice! I made a solution by making fixed circular list of pointers. Maybe somebody find it useful in same cases as mine.

Code: Select all

MODULE MauV4;

  IMPORT Out, Main, MAU, Random;
  
  TYPE
    Event = POINTER TO RECORD
      data: INTEGER;
      next: Event
    END;

  VAR
    list , r, w: Event;

  PROCEDURE InitList;
    VAR item: Event; i: INTEGER;
  BEGIN
    NEW(list );
    item := list ;
    FOR i := 1 TO 20 DO
      NEW(item.next);
      item := item.next
    END;
    item.next := list;
    r := list;
    w := list;
  END InitList;
  
  PROCEDURE Add(VAR a: INTEGER): BOOLEAN;
    VAR item: Event; res: BOOLEAN;
  BEGIN
    (* If were any place in list *)
    IF w.next # r THEN
      w.data := a;
      (* Make a step in the cycle *)
      w := w.next;
      res := TRUE
    ELSE
      res := FALSE
    END;
    RETURN res
  END Add;
  
  PROCEDURE Do(): BOOLEAN;
    VAR res: BOOLEAN;
  BEGIN
    (* If something is written in the list *)
    IF r # w  THEN
      (* Do processing of data *)
      Out.String("data: "); Out.Int(r.data, 7); Out.String("mem free: "); Out.Int(MAU.MemAvailable(), 4); Out.Ln;
      (* Make a step in the cycle *)
      r := r.next;
      res := TRUE
    ELSE
      res := FALSE
    END
    RETURN res
  END Do;
  
  PROCEDURE Run;
    VAR rand, counter: INTEGER;
  BEGIN
    InitList; (* Init circular list *)
    counter := 1;
    
    WHILE TRUE DO
      (* Irregular addition of data to list *)
      rand := Random.Next(1000);
      IF rand > 500 THEN
        IF Add(counter) THEN
          INC(counter)
        ELSE
          Out.String("LIST IS FULL"); Out.Ln
        END
      END;
      (* Irregular data processing *)
      rand := Random.Next(1000);
      IF rand > 500 THEN
        IF ~ Do() THEN
          Out.String("LIST IS EMPTY"); Out.Ln
        END
      END
    END
  END Run;

BEGIN
  Run

END MauV4.