mi-malloc 1.8/2.1
 
Lade...
Suche...
Keine Treffer
Malloc überschreiben

Das Überschreiben des Standard-malloc (und new) kann entweder dynamisch oder statisch erfolgen.

Dynamisches Überschreiben

Dies ist die empfohlene Methode, um die Standard-malloc-Schnittstelle zu überschreiben.

Dynamisches Überschreiben unter Linux, BSD

Auf diesen ELF-basierten Systemen laden wir die mimalloc-Shared-Bibliothek vor, sodass alle Aufrufe der Standard-malloc-Schnittstelle auf die mimalloc-Bibliothek aufgelöst werden.

> env LD_PRELOAD=/usr/lib/libmimalloc.so meinprogramm

Sie können zusätzliche Umgebungsvariablen festlegen, um zu überprüfen, ob mimalloc läuft, z. B.

> env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so meinprogramm

oder mit der Debug-Version ausführen, um detaillierte Statistiken zu erhalten

> env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so meinprogramm

Dynamisches Überschreiben unter MacOS

Unter macOS können wir ebenfalls die mimalloc-Shared-Bibliothek vorladen, sodass alle Aufrufe der Standard-malloc-Schnittstelle auf die mimalloc-Bibliothek aufgelöst werden.

> env DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib meinprogramm

Beachten Sie, dass bestimmte Sicherheitsbeschränkungen gelten können, wenn dies von der Shell aus geschieht.

Dynamisches Überschreiben unter Windows

Das dynamische Überschreiben von mimalloc unter Windows ist robust und hat den besonderen Vorteil, alle malloc/free-Aufrufe umleiten zu können, die über den (dynamischen) C-Laufzeit-Allocator erfolgen, einschließlich derer aus anderen DLLs oder Bibliotheken. Da es alle Allokationsaufrufe auf niedriger Ebene abfängt, kann es zuverlässig für große Programme verwendet werden, die andere Drittanbieterkomponenten enthalten. Es gibt vier Voraussetzungen, damit das Überschreiben gut funktioniert:

  1. Verwenden Sie die C-Laufzeitbibliothek als DLL (mit dem Schalter /MD oder /MDd).
  2. Verknüpfen Sie Ihr Programm explizit mit der Exportbibliothek mimalloc.lib für die mimalloc.dll. (die mit -DMI_OVERRIDE=ON kompiliert sein muss, was jedoch Standard ist). Um sicherzustellen, dass die mimalloc.dll zur Laufzeit tatsächlich geladen wird, ist es am einfachsten, einen Aufruf der mimalloc-API in der main-Funktion einzufügen, wie z. B. mi_version() (oder verwenden Sie den Schalter /include:mi_version im Linkerbefehl oder ähnlich #pragma comment(linker, "/include:mi_version") in einer Quelldatei). Das Projekt mimalloc-test-override zeigt ein Beispiel dafür.
  3. Die mimalloc-redirect.dll muss zur Laufzeit im selben Verzeichnis wie die Haupt-mimalloc.dll abgelegt werden (da sie eine Abhängigkeit dieser DLL ist). Die Umleitungs-DLL stellt sicher, dass alle Aufrufe der C-Laufzeit-malloc-API an mimalloc-Funktionen (die sich in mimalloc.dll befinden) umgeleitet werden.
  4. Stellen Sie sicher, dass die mimalloc.dll so früh wie möglich in der Importliste der endgültigen ausführbaren Datei steht (damit sie alle potenziellen Allokationen abfangen kann). Sie können minject -l <exe> verwenden, um dies bei Bedarf zu überprüfen.

Für die beste Leistung unter Windows mit C++ wird auch empfohlen, die new/delete-Operationen zu überschreiben (durch Einbeziehen von mimalloc-new-delete.h in eine einzige(!) Quelldatei Ihres Projekts).

Die Umgebungsvariable MIMALLOC_DISABLE_REDIRECT=1 kann verwendet werden, um das dynamische Überschreiben zur Laufzeit zu deaktivieren. Verwenden Sie MIMALLOC_VERBOSE=1, um zu überprüfen, ob mimalloc erfolgreich umgeleitet wurde.

Für andere Plattformen als x64 benötigen Sie möglicherweise eine spezielle [Umleitungs-DLL](bin). Darüber hinaus können wir nicht immer eine ausführbare Datei neu verknüpfen oder sicherstellen, dass mimalloc.dll zuerst in der Importtabelle steht. In solchen Fällen kann das Tool [minject](bin) verwendet werden, um die Importtabellen der ausführbaren Datei zu patchen.

Statisches Überschreiben

Auf Unix-ähnlichen Systemen können Sie auch statisch mit mimalloc verknüpfen, um die Standard-malloc-Schnittstelle zu überschreiben. Die empfohlene Methode ist, das finale Programm mit der einzelnen Objektdatei von mimalloc (mimalloc.o) zu verknüpfen. Wir verwenden eine Objektdatei anstelle einer Bibliotheksdatei, da Linker dieser gegenüber Archiven den Vorzug geben, um Symbole aufzulösen. Um sicherzustellen, dass die Standard-malloc-Schnittstelle auf die mimalloc-Bibliothek aufgelöst wird, verknüpfen Sie sie als erste Objektdatei. Zum Beispiel:

> gcc -o meinprogramm mimalloc.o meineDatei1.c ...

Eine weitere statische Überschreibmethode, die auf allen Plattformen funktioniert, ist die statische Verknüpfung mit mimalloc (wie in der Einleitung gezeigt) und das Einbeziehen einer Headerdatei in jede Quelldatei, die malloc usw. zu mi_malloc neu definiert. Dies wird von mimalloc-override.h bereitgestellt. Dies funktioniert jedoch nur zuverlässig, wenn alle Quellen unter Ihrer Kontrolle sind, da ansonsten Zeiger von verschiedenen Heaps gemischt werden könnten!

Liste der Überschreibungen

Die spezifischen Funktionen, die auf die mimalloc-Bibliothek umgeleitet werden, sind:

// C
void* malloc(size_t size);
void* calloc(size_t size, size_t n);
void* realloc(void* p, size_t newsize);
void free(void* p);
void* aligned_alloc(size_t alignment, size_t size);
char* strdup(const char* s);
char* strndup(const char* s, size_t n);
char* realpath(const char* fname, char* resolved_name);
// C++
void operator delete(void* p);
void operator delete[](void* p);
void* operator new(std::size_t n) noexcept(false);
void* operator new[](std::size_t n) noexcept(false);
void* operator new( std::size_t n, std::align_val_t align) noexcept(false);
void* operator new[]( std::size_t n, std::align_val_t align) noexcept(false);
void* operator new ( std::size_t count, const std::nothrow_t& tag);
void* operator new[]( std::size_t count, const std::nothrow_t& tag);
void* operator new ( std::size_t count, std::align_val_t al, const std::nothrow_t&);
void* operator new[]( std::size_t count, std::align_val_t al, const std::nothrow_t&);
// Posix
int posix_memalign(void** p, size_t alignment, size_t size);
// Linux
void* memalign(size_t alignment, size_t size);
void* valloc(size_t size);
void* pvalloc(size_t size);
size_t malloc_usable_size(void *p);
void* reallocf(void* p, size_t newsize);
// macOS
void vfree(void* p);
size_t malloc_size(const void* p);
size_t malloc_good_size(size_t size);
// BSD
void* reallocarray( void* p, size_t count, size_t size );
void* reallocf(void* p, size_t newsize);
void cfree(void* p);
// NetBSD
int reallocarr(void* p, size_t count, size_t size);
// Windows
void* _expand(void* p, size_t newsize);
size_t _msize(void* p);
void* _malloc_dbg(size_t size, int block_type, const char* fname, int line);
void* _realloc_dbg(void* p, size_t newsize, int block_type, const char* fname, int line);
void* _calloc_dbg(size_t count, size_t size, int block_type, const char* fname, int line);
void* _expand_dbg(void* p, size_t size, int block_type, const char* fname, int line);
size_t _msize_dbg(void* p, int block_type);
void _free_dbg(void* p, int block_type);