2009-07-24 2 views
11

Hat eine gemeinsam genutzte C++ - Bibliothek einen eigenen Speicherplatz? Oder teilt es sich den Anruferprozess?Gemeinsamer Bibliotheksspeicherbereich

Ich habe eine gemeinsame Bibliothek, die einige Klassen und Wrapper-Funktionen enthält. Eine dieser Wrapper-Funktion ist irgendwie:

libXXX_construct(), die ein Objekt initialisiert und den Zeiger auf das Objekt zurückgibt.

Sobald ich libXXX_construct() in einem Aufrufer-Programm verwendet, wo ist das Objekt platziert? Ist es im Speicherbereich "Aufrufer" oder ist es im Speicher der Bibliothek?

Antwort

7

Eine verknüpfte Instanz der gemeinsam genutzten Bibliothek teilt den Speicherbereich der Instanz der ausführbaren Datei, die direkt oder indirekt mit ihr verbunden ist. Dies gilt sowohl für Windows als auch für die UN * X-ähnlichen Betriebssysteme. Beachten Sie, dass dies bedeutet, dass statische Variablen in gemeinsam genutzten Bibliotheken keine Möglichkeit der Kommunikation zwischen Prozessen darstellen (was viele Leute denken).

+0

Was ist, wenn die ausführbare Datei, die mit der sharedlibrary verbunden ist, auch eine gemeinsam genutzte Bibliothek ist? Wird das Objekt im inneren .so im selben Speicherbereich des mains erstellt (der letzteres anruft .so) – nick2k3

+0

Es gibt immer nur einen Speicherplatz. –

+0

Vielen Dank. – nick2k3

2

Alle gemeinsam genutzten Bibliotheken teilen sich den virtuellen Speicher ihres Prozesses. (Einschließlich der wichtigsten ausführbare Datei selbst)

0

Ihr Objekt existiert in dem Speicherplatz des Anrufers (in der Tat derjenige Speicherplatz zwischen der Bibliothek geteilt und dem Hauptprogramm)

0

Der Anteil Adressraum, so dass Sie Zeiger teilen können, aber Sie teilen nicht Zuordner (zumindest nicht auf Windows).

Dies bedeutet, wenn Sie neu aufrufen, um ein Objekt in einer gemeinsam genutzten Bibliothek zuzuweisen, müssen Sie löschen in der gleichen Bibliothek aufrufen oder seltsame Dinge passieren können.

+1

Dieses Problem wurde behoben. Dies galt für die ältere Entwicklung auf Windows, mit der modernen Entwicklung ist es kein gültiges Problem mehr. Stellen Sie nur sicher, dass Sie alle DLL mit der freigegebenen Version der Laufzeit verknüpfen. –

+0

Danke, ich wusste nicht, dass sich das geändert hat. Die Probleme, die ich in letzter Zeit hatte, waren höchstwahrscheinlich zwei Instanzen der statischen Laufzeitbibliothek, die nicht zwischen der ausführbaren Datei und der DLL geteilt wird. – Laserallan

0

Die gemeinsam genutzte Bibliothek hat denselben Adressraum wie ihr Host-Prozess. Es muss so sein, sonst wären Sie nicht in der Lage, Zeiger von einem Modul zum anderen zu übergeben, da sie nicht in der Lage wären, sie zu dereferenzieren.

Aber obwohl sie im selben Adressraum sind, bedeutet das nicht, dass sie alle denselben Speichermanager verwenden. Wenn Sie eine Funktion bereitstellen, die Speicher im Auftrag des Aufrufers zuweist, sollten Sie eine entsprechende Funktion bereitstellen, um diesen Speicher freizugeben, z. B. libXXX_destroy().

+0

Könnten Sie diesen Speichermanager weiter erklären? – nick2k3

+1

Der Speicher-Manager ist die Sache, die scheint, Speicher dynamisch für Sie zuzuweisen, wenn Sie Dinge wie malloc() oder jetzt tun. Dies steht nur im Zusammenhang mit dem Problem mit dem Adressraum der Bibliothek, da Sie verschiedene Manager in derselben .c- oder .cpp-Quelldatei verwenden können, ganz abgesehen von verschiedenen Bibliotheken. –

+0

@Neil. Ich denke, der Autor bezieht sich auf das Problem, wenn jede DLL statisch mit der Laufzeitbibliothek verbunden war. Dies führte dazu, dass jede DLL im Grunde ihre eigene Speicherverwaltung hatte (daher konnte eine DLL Speicher, der von einer anderen DLL zugewiesen wurde, nicht freigeben). Dieses Problem wurde lange mit der Verwendung einer gemeinsamen DLL für die Laufzeitbibliotheken gelöst. –

2

Sofern nicht anders angegeben, teilt eine gemeinsam genutzte Bibliothek den Arbeitsspeicher mit dem Prozess, der sie hostet. Jede Prozessinstanz erhält dann ihre eigene Kopie.

Unter Windows ist es jedoch möglich, gemeinsame Variablen zu erstellen, die eine Kommunikation zwischen Prozessen ermöglichen. Sie tun dies, indem Sie sie in die richtige Art von Segment setzen. Standardmäßig verwendet Windows zwei Arten von Segmenten: Datensegmente sind nicht gemeinsam genutzt, während Codesegmente schreibgeschützt und freigegeben sind. Die Lese-Schreib- und geteilten Attribute sind jedoch orthogonal. Ein gemeinsam genutztes Lese-/Schreib-Segment in einer Bibliothek kann verwendet werden, um gemeinsam genutzte Variablen zu speichern, und es wird überleben, bis der letzte Prozess beendet wird.

Seien Sie vorsichtig mit C++, denn das wird glücklich machen, Konstruktoren und Destruktoren auf Prozessstart & Exit, auch wenn Sie Variablen in gemeinsamen Segmenten setzen. Weitere Informationen finden Sie unter Peering Inside the PE: A Tour of the Win32 Portable Executable File Format part 2 von Matt Pietrek.

+0

Das geht über den Rahmen von C++ hinaus (Sie nehmen an Assembly-Ebene herum). Es gibt gute Gründe, dies NICHT zu tun (insbesondere warum sie nicht als Sprachkonstrukte enthalten sind). Verwenden Sie das Betriebssystem, um Kommunikationsfunktionen zwischen Prozessen bereitzustellen. Es ist da, um das Zeug sicher zu machen. –

+0

Shared Libraries, um die es in dieser Frage geht, gehen über C++ hinaus, ebenso wie IPC. C++ hat nur eine externe oder interne Verbindung, es hat keine Vorstellung davon, dass mehrere Programme gleichzeitig laufen, außer in Bezug auf Signale. –

+0

@Martin York: Nun, wenn Sie versuchen, ein existierendes Programm zu verstehen (und die Frage kann gelesen werden, um das zu suggerieren), müssen Sie sich der Möglichkeit stellen, dass der vorherige Autor tatsächlich so getüftelt hat. Sie irren sich über den Grund, warum sie nicht in der Sprache enthalten sind - das liegt daran, dass diese Tricks inhärent plattformspezifisch sind und ISO C++ nicht. – MSalters

0

Es stimmt, dass eine Bibliothek in jedem Prozess, der sie lädt, Speicher belegt.Wenn jedoch mehrere Prozesse dieselbe DLL laden, werden zumindest unter Windows die nicht geänderten Seiten (einschließlich aller Codepages) in aller Ruhe unter den Deckblättern geteilt. Außerdem belegen sie in der Auslagerungsdatei keinen Platz, da sie von der Originaldatei unterstützt werden.

Ich glaube, das ist komplizierter für. NET, aufgrund der JIT-Kompilierung, aber würde immer noch für NGENed-Baugruppen gelten.

bearbeiten

Dies ist ein Detail der VM. Sie können jedoch auch flag ein Segment in einer DLL für alle Prozesse freigeben.