Jede Art von "Pool" ist wirklich nur Ressourcen, die Sie im Voraus erworben/initialisiert haben, so dass sie bereits bereit sind, zu gehen und nicht bei jeder Kundenanforderung zu vergeben. Wenn Clients ihre Verwendung beenden, kehrt die Ressource in den Pool zurück, anstatt zerstört zu werden.
Speicherpools sind im Grunde nur Speicher, den Sie im Voraus zugewiesen haben (und normalerweise in großen Blöcken). Beispielsweise könnten Sie im Voraus 4 Kilobyte Speicher reservieren. Wenn ein Client 64 Byte Speicher anfordert, übergeben Sie ihm einfach einen Zeiger auf einen unbenutzten Speicherplatz in diesem Speicherpool, damit er lesen und schreiben kann, was er will. Wenn der Client fertig ist, können Sie diesen Speicherbereich einfach als nicht mehr verwendet markieren.
Als einfaches Beispiel, das mit Ausrichtung, Sicherheit nicht stört, oder nicht verwendete Rückkehr (frei) Speicher zurück zum Pool:
class MemoryPool
{
public:
MemoryPool(): ptr(mem)
{
}
void* allocate(int mem_size)
{
assert((ptr + mem_size) <= (mem + sizeof mem) && "Pool exhausted!");
void* mem = ptr;
ptr += mem_size;
return mem;
}
private:
MemoryPool(const MemoryPool&);
MemoryPool& operator=(const MemoryPool&);
char mem[4096];
char* ptr;
};
...
{
MemoryPool pool;
// Allocate an instance of `Foo` into a chunk returned by the memory pool.
Foo* foo = new(pool.allocate(sizeof(Foo))) Foo;
...
// Invoke the dtor manually since we used placement new.
foo->~Foo();
}
Diese effektiv Speicher nur die Bündelung von dem Stapel.Eine komplexere Implementierung könnte Blockierungen zusammenketten und einige Verzweigungen ausführen, um zu sehen, ob ein Block voll ist, um nicht zu viel Speicher zu verbrauchen, mit Blöcken fester Größe umgehen, die Vereinigungen sind (freie Knoten, Speicher für den Client) es muss definitiv mit der Ausrichtung umgehen (am einfachsten ist es, die Speicherblöcke auszurichten und jedem Block einen Padding hinzuzufügen, um den nächsten auszurichten).
Mehr Phantasie wäre Buddy Allokatoren, Platten, diejenigen, die Anpassung Algorithmen, etc. Implementieren eines Zuordners ist nicht so verschieden von einer Datenstruktur, aber Sie knietief in rohen Bits und Bytes, müssen über Dinge wie Ausrichtung denken , und kann den Inhalt nicht mischen (vorhandene Zeiger auf den verwendeten Speicher können nicht ungültig gemacht werden). Wie Datenstrukturen gibt es nicht wirklich einen goldenen Standard, der sagt: "Du sollst das tun". Es gibt eine Vielzahl von ihnen, jede mit ihren eigenen Stärken und Schwächen, aber es gibt einige besonders beliebte Algorithmen für die Speicherzuweisung.
Das Implementieren von Zuordnungen ist etwas, was ich vielen C- und C++ - Entwicklern empfehlen würde, um mit der Art und Weise, wie die Speicherverwaltung ein bisschen besser funktioniert, aufzufrischen. Es kann Ihnen ein wenig bewusster machen, wie der angeforderte Speicher mit den Datenstrukturen, die diese verwenden, verbunden ist, und eröffnet auch eine ganz neue Tür für Optimierungsmöglichkeiten, ohne neue Datenstrukturen zu verwenden. Es kann auch Datenstrukturen wie verknüpfte Listen, die normalerweise nicht sehr effizient sind, viel nützlicher machen und Versuchungen reduzieren, undurchsichtige/abstrakte Typen undurchsichtiger zu machen, um den Heap-Overhead zu vermeiden. Es kann jedoch eine anfängliche Aufregung geben, die Sie dazu bringen könnte, benutzerdefinierte Allokatoren für alles zu schuhen, nur um später die zusätzliche Belastung zu bereuen (besonders wenn Sie in Ihrer Aufregung Probleme wie Fadensicherheit und Ausrichtung vergessen). Es lohnt sich, sich dort zu entspannen. Wie bei jeder Mikrooptimierung wird sie im Allgemeinen am besten im Nachhinein und mit einem Profiler in der Hand angewendet.
Werfen Sie einen Blick auf [boost :: pool] (http://www.boost.org/doc/libs/1_58_0/libs/pool/doc/html/index.html) – rds504
Siehe auch: http: // stackoverflow.com/questions/16378306/c11-memory-pool-design-pattern – NathanOliver
Vielleicht hilft das: [Speicherverwaltung] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa366779%28v = vs.85% 29.aspx) – Zero