PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : memory tracking Frage bezüglich Flipcode tut


liquid
2003-11-19, 20:24:51
Hi Leute,

hier bei Flipcode (http://www.flipcode.com/tutorials/tut_memleak.shtml) gibts ein schönes Tutorial über das Tracking von Speicheranforderung, um mem-leaks zu vermeiden bzw. zu verhindern.

Naja, ich hab mir das heute mal angeguckt und bin mir da nicht so sicher, ob das alles auch so koscher ist.

#ifdef _DEBUG
inline void * __cdecl operator new(unsigned int size,
const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, file, line);
return(ptr);
};
inline void __cdecl operator delete(void *p)
{
RemoveTrack((DWORD)p);
free(p);
};
#endif

Nehmen wir new. Speicher wird mithilfe von malloc allokiert (ist allozieren eigentlich dasselbe?), aber wird dabei nicht NUR Speicher angefordert? Ich meine malloc ruft doch nicht den Konstruktor des Objektes auf das ich erstelle oder sehe ich das falsch?
Oder wird bei der ganzen Sache nur der "low-level" new überschrieben, der allein für den Speicher zuständig ist? Ich will nicht etwas in mein Programm einbaun, was nachher zu komischen Fehlern führt, die nicht nachzuvollziehen sind.

cya
liquid

zeckensack
2003-11-20, 20:08:00
Deine Zweifel sind berechtigt. Ich würde dringend davon abraten, diesen Code zu verwenden.

1)Funktioniert - wie du schon richtig erkannt hast - nur mit structs und Basistypen. Keine Konstruktoren/Destruktoren.

2)Überschreibt Namen aus der Standard-Library. Kein Programm sollte sowas tun.


debug_new oä wäre ein sinnvoller Name für die Funktion (ganz davon abgesehen, daß sie so nicht funktionieren kann).

Vorschlag: rein über den Präprozessor lösen
#ifdef _DEBUG
#define SAFE_NEW(a) (AddTrack(new a);)
#define SAFE_NEW_ARRAY(a,b) (AddTrack(new[b] a);)
#define SAFE_DELETE(a) {RemoveTrack(a); delete a; a=NULL;}
#define SAFE_DELETE_ARRAY(a) {RemoveTrack(a); delete[] a; a=NULL;}
#else
#define SAFE_NEW(a) (new a)
#define SAFE_NEW_ARRAY(a,b) (new[b] a)
#define SAFE_DELETE(a) {delete a; a=NULL;}
#define SAFE_DELETE_ARRAY(a) {delete[] a; a=NULL;}
#endif

Verbleibendes Problem:
AddTrack muß den Pointer zurückgeben, sonst funktioniert hier garnichts mehr.
Dieser Pointer muß außerdem den korrekten Typ haben (void* würde nur dazu führen, daß man bei jeder Zuweisung casten muß). AddTrack sollte deswegen am besten eine Template-Funktion sein.

Demirug
2003-11-20, 20:42:54
zeckensack, das globale Überladen von new funktioniert ausgezeichnet. Der Compiler ruft den globalen new Operator auf um Speicher anzufordern und danach wird der entsprechenden Konstruktor ausgeführt.

Nichts anderes machen die meisten kaufbare Memtracker auch. Der in VC++ eingebauten Memtracker arbeitet genauso.

liquid
2003-11-20, 20:43:13
Thx zecki, werde den Code entsprechend umbauen.

cya
liquid

EDIT: Hmm, hat Demi doch recht? Bitte um Klärung!

zeckensack
2003-11-20, 20:52:23
Original geschrieben von Demirug
zeckensack, das globale Überladen von new funktioniert ausgezeichnet. Der Compiler ruft den globalen new Operator auf um Speicher anzufordern und danach wird der entsprechenden Konstruktor ausgeführt.

Nichts anderes machen die meisten kaufbare Memtracker auch. Der in VC++ eingebauten Memtracker arbeitet genauso. Ah, danke, das wußte ich nicht. Macht aber nach kurzem Wühlen durchaus Sinn :)

Zusammegefaßt etwa so:
Class::operator new ruft normalerweise ::new auf, um Speicher anzufordern, und dann den Konstruktor.
Class::operator delete ruft ::delete auf, nachdem der Destruktor seine Arbeit getan hat.

=> ::new und ::delete können sicher überladen werden.

Korrekt?

Demirug
2003-11-20, 21:01:42
Original geschrieben von zeckensack
Ah, danke, das wußte ich nicht. Macht aber nach kurzem Wühlen durchaus Sinn :)

Zusammegefaßt etwa so:
Class::operator new ruft normalerweise ::new auf, um Speicher anzufordern, und dann den Konstruktor.
Class::operator delete ruft ::delete auf, nachdem der Destruktor seine Arbeit getan hat.

=> ::new und ::delete können sicher überladen werden.

Korrekt?

Genau. Wobei bei dem Memtracker noch eine Besonderheit ins Spiel kommt. In diesem Fall wird bei new Operator ja eigentlich nicht der globale new Operator überladen sondern ein neuer geschaffen welcher zwei zusätzliche Parameter enthält. Durch einen #define den liquid nicht angeben hat wird dann aus dem normalen new ein new mit den beiden zusätzlichen Parametern (File, Line) gemacht.

Normalerweise dienen diese globalen new Operatoren mit zusätzlichen Parametern dazu zusätzliche Informationen bezüglich der Speicherreservierung anzugeben. Bei einem System das zum Beispiel über unterschiedlich (schnelle) Speicher verfügt kann man so angeben in welchem Speicher das Objekt plaziert werden soll. Ist zum Beispiel für eine dynamische Speicherverwaltung bei Konsolen ganz brauchbar.