AVR: Wie entfernt man malloc() und free()?

OP #5343883
Lesenswert?

Hallo zusammen,

natürlich verwende ich (bewusst) keine dynamische Speicherverwaltung und 
entdecke aber gerade via avr-nm, dass die Funktionen malloc() und free() 
enthalten sind und jeweils unnötig Speicher fressen (304 + 274 bytes).

Ich suche mich gerade tot im Internet (-dead_strip etc.), finde aber 
absolut keinen Tipp, wie man die Funktionen los wird.
Eine leere Implementierung funktioniert nicht.
Auch die gcc-Flags "-why_live symbol_name" funktionieren beim AVR nicht.
Ich vermute ja irgendeine dumme Abhängigkeit zu irgendeiner 
Standard-Funktion...

Hat jemand irgendein Tipp?

Viele Grüße
Andreas
#5343894
Lesenswert?

Andreas J. schrieb:
> natürlich verwende ich (bewusst) keine dynamische Speicherverwaltung und
> entdecke aber gerade via avr-nm, dass die Funktionen malloc() und free()
> enthalten sind und jeweils unnötig Speicher fressen (304 + 274 bytes).

Wenn sie enthalten sind, werden sie genutzt, wenn auch über Bande. Und 
ihr Speicherverbrauch ist dann nicht unnütz.

> Ich vermute ja irgendeine dumme Abhängigkeit zu irgendeiner
> Standard-Funktion...
>
> Hat jemand irgendein Tipp?

Disassembliere dein .elf Binary: "avr-objdump -d -S main.elf". Wenn du 
mit Debug-Symbolen compiliert hast (es gibt keinen Grund, der dagegen 
spräche) hast du nachher an jedem rcall den Namen der aufgerufenen 
Funktion als Kommentar. Und dann kannst du dich rückwärts durchhangeln, 
welche Funktion(alität) da auf malloc() und free() beharrt.

Nochwas. Ich habe mittlerweile eigentlich immer die folgenden Optionen 
in meinen CFLAGS: "-fdata-sections -ffunction-sections -flto 
-Wl,--gc-sections". Die Bedeutlung solltest du selber nachschlagen.
OP #5343917
Lesenswert?

Super, Danke Dir für den Tipp!

malloc() wird nur von atexit() aufgerufen.

Und aus irgendeinem Grund ruft der Compiler am Ende des Konstruktors:

static TinyController controller(serial);

... die Funktion atexit() auf. Die einzige Stelle.

Da ich auch __cxa_guard_acquire etc. loswerden will, entsorge ich gerade 
alle pure virtual functions.
Reicht aber nicht, sie werden auch durch den Konstruktor erzwungen.

Ich probiere mal weiter...
Gast #5343964
Lesenswert?

Versuche mal folgende Compiler-Optionen:
-fno-use-cxa-atexit -ffunction-sections -fdata-sections -flto
Und folgende Linker-Optionen
-Wl,--gc-sections -flto

Das könnte die Funktionen wegoptimieren. Definiere eine leere Funktion 
"__cxa_pure_virtual" um die Behandlung rein virtueller Funktionen 
loszuwerden.
OP #5343979
Lesenswert?

Hilft leider nicht...

Sobald ich meine C++ - Instanz statisch mache, ziehe ich mir atexit() 
und damit malloc() rein. Das wird der implizite statische Destruktor 
sein.
Ist sie nicht statisch, dann generiert der Compiler ja auch einen 
impliziten Destruktor, bei diesem ist aber offensichtlich kein 
atexit() notwendig, und das ist jetzt meine Lösung.

Ich müsste dem Compiler sagen können, dass er keine (statischen) 
Destruktoren generieren soll, da wir ja eh eine Endlosschleife in main() 
haben.
Ich brauche überhaupt keine Destruktoren...

Aber ob es dafür ein Flag gibt? Ich finde jedenfalls keins...
OP #5343987
Lesenswert?

1
#include "Kernel/Clock.h"
2
#include "Kernel/Serial.h"
3
#include "AqMod/TinyController.h"
4

5
#include <avr/interrupt.h>
6
#include <avr/io.h>
7

8
using namespace AJ::Kernel;
9
using namespace AJ::AqMod;
10

11
extern "C" void __cxa_pure_virtual() 
12
{ 
13
  while (true);
14
}
15

16
__extension__ typedef int __guard __attribute__((mode (__DI__)));
17

18
extern "C" int __cxa_guard_acquire(__guard* g)
19
{
20
  return !*(char *)(g);
21
}
22

23
extern "C" void __cxa_guard_release(__guard* g)
24
{
25
  *(char *)g = 1;
26
}
27

28
extern "C" void __cxa_guard_abort(__guard*)
29
{
30
}
31

32
int main(void)
33
{
34
  //byte resetReason = MCUSR;
35
  //MCUSR = 0x00;
36
  
37
  Clock::Initialize();
38
  static Serial serial(EBaudRate::BR9600);
39
  static TinyController controller(serial);
40
  
41
  sei();
42
  
43
    while (true) 
44
    {
45
    controller.Loop();
46
    }
47
}

Program Memory Usage   :  15624 bytes   95,4 % Full
Data Memory Usage   :  740 bytes   72,3 % Full
EEPROM Memory Usage   :  96 bytes   18,8 % Full
1
#include "Kernel/Clock.h"
2
#include "Kernel/Serial.h"
3
#include "AqMod/TinyController.h"
4

5
#include <avr/interrupt.h>
6
#include <avr/io.h>
7

8
using namespace AJ::Kernel;
9
using namespace AJ::AqMod;
10

11
extern "C" void __cxa_pure_virtual() 
12
{ 
13
  while (true);
14
}
15

16
int main(void)
17
{
18
  //byte resetReason = MCUSR;
19
  //MCUSR = 0x00;
20
  
21
  Clock::Initialize();
22
  Serial serial(EBaudRate::BR9600);
23
  TinyController controller(serial);
24
  
25
  sei();
26
  
27
    while (true) 
28
    {
29
    controller.Loop();
30
    }
31
}

Program Memory Usage   :  14860 bytes   90,7 % Full
Data Memory Usage   :  287 bytes   28,0 % Full
EEPROM Memory Usage   :  96 bytes   18,8 % Full
Gast #5344004
Lesenswert?

Mach die Instanzen einfach global, vor das main(), egal ob mit static 
oder ohne. So wird das Speicher im .data Segment gezählt, und der 
Destruktor wird nie aufgerufen, und du brauchst die Locks nicht.
OP #5344028
Lesenswert?

Die Instanzen global zu machen hatte ich mir auch schon überlegt (musste 
nur auf Late Binding umstellen, ist aber eh sauberer)...

Und merkwürdigerweise generiert der Compiler auch bei static keinen 
Destruktor mit atexit() mehr. Wobei ich static jetzt natürlich weglasse, 
das war ja nur ein "Trick", den echten Speicherverbrauch (trotz 
Instanzzierung in main()) zu sehen...

Danke Dir, wieder was gelernt ;) !
Gast #5344031
Lesenswert?

Andreas J. schrieb:
> Und merkwürdigerweise generiert der Compiler auch bei static keinen
> Destruktor mit atexit() mehr.

Weil static bei globalen Variablen eine komplett andere Bedeutung hat, 
es verhindert einfach nur den Zugriff auf die Variable aus anderen 
Source-Files, denn die Variable erhält kein Symbol mehr. static 
innerhalb von Funktionen impliziert eine relativ komplexe Logik mithilfe 
von Locks die das Objekt erst dann anlegt, wenn die Funktion zum ersten 
Mal aufgerufen wird.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren