2010-12-06 6 views
6

Ich versuche, einen speziellen Build einer großen monolithischen Anwendung zu erzeugen. Das Problem, das ich zu lösen versuche, ist das Nachverfolgen von schwer zu reproduzierenden Speicherzuweisungen (30 - 80 Gigabyte, nach den Betriebssystemberichten zu beurteilen). Ich glaube, das Problem ist ein std :: Vektor auf einen negativen 32-Bit-Integer-Wert geändert. Die einzige Plattform, die dieses Verhalten zeigt, ist Solaris (vielleicht ist es die einzige Plattform, die es schafft, solche Stücke zusammenhängender Speicher erfolgreich zuzuordnen). Kann ich std :: vector global durch meine Klasse ersetzen, indem ich alle Aufrufe an den realen Vektor delegiere und nach verdächtigen Zuweisungen Ausschau halte? (size > 0x7FFFFFFFu)? Vielleicht den Konstruktor, der die Methoden size_t und resize() verwendet, selektiv ersetzen? Vielleicht sogar den globalen Betreiber neu entführen?Overriding globaler Operator neu zu verfolgen große Speicherzuordnungen?

+1

ein 32-Bit-Wert kann nicht IMO Ergebnis 30-80 Gigabyte, meinst du 64 Bit –

+0

Ein Array von 0xFFFFFFFF 8-Byte-Strukturen dauert ~ 34 Gigabyte. –

+0

Ich stehe korrigierte –

Antwort

5

Warum nicht so etwas tun?

void *operator new(size_t size) 
{ 
    // if (size > MAX_SIZE) ... 
    return malloc(size); 
} 

void *operator new [](size_t size) 
{ 
    // if (size > MAX_SIZE) ... 
    return malloc(size); 
} 

einen Haltepunkt in der if einstellen würde sofort das Problem finden.

+0

Ja, das möchte ich erreichen. Natürlich ist "operator new" bereits in der Standardbibliothek der Plattform definiert, sodass ich nicht einfach eine zweite Implementierung bereitstellen kann. –

+1

Ja können Sie. Hast du es versucht? Erhalten Sie Verknüpfungsfehler? – detunized

+0

Es wäre toll, wenn ich das einfach so machen könnte. Ich werde es versuchen. –

2

Sie können zum Zeitpunkt der Konstruktion einen benutzerdefinierten Zuordner auf Ihrem Vektor bereitstellen.

Sie könnten einfach an std::allocator delegieren, und Firewall die angeforderte Speichergröße, in der ersten Instanz.

+0

Sie sehen, das Problem ist, ich habe keine Ahnung, welcher Teil des Codes falsch verhält. Es ist kaum möglich, die gesamte Codebasis (einschließlich Bibliotheken von Drittanbietern) mit benutzerdefinierten Zuordnern zu ändern, an denen überall ein Vektor verwendet wird. –

+0

Ja, das ist dann schwieriger. Das q liest, als ob Sie vielleicht bereits wissen, um welchen Vektor es sich handelt. Bietet Ihre Plattform die Möglichkeit, Heap-Blöcke durch Erstellen von Callstacks zu kennzeichnen? –

+0

Ich kann die Anrufliste protokollieren, wenn ich einen verdächtigen Zustand feststelle. Die Frage ist, wie man es global erkennt, ohne jede einzelne Klasse mit einem Vektor zu ändern. –

0

Werfen Sie einen Blick auf die Implementierung der std::vector Klasse auf der Problemplattform. Bei jeder Implementierung wird die Speicherverwaltung anders gehandhabt (z. B. ein Doppeltes des derzeit zugewiesenen Speicherplatzes, wenn Sie ein Objekt außerhalb der aktuellen Zuordnungsgröße des Vektors hinzufügen). Wenn Ihre Objekte ausreichend groß sind und/oder Sie eine große Anzahl von Einträgen zu dem Vektor hinzufügen, wäre es möglich, zu versuchen, über den verfügbaren (zusammenhängenden) Speicher auf dem Computer zu reservieren. Wenn dies der Fall ist, sollten Sie sich einen benutzerdefinierten Zuordner für diesen Vektor ansehen.

Wenn Sie so viele große Objekte in einem Vektor speichern, können Sie sich eine andere Sammlung ansehen (z. B. std::list) oder versuchen, Zeiger anstelle von tatsächlichen Objekten zu speichern.

+0

Das Problem, das ich zu lösen versuche, ist nicht, wie man den Code ändert, um weniger Speicher zu verwenden.Ich versuche, den fehlerhaften Code zu finden, der 'vector.resize ((size_t) (- 1))' effektiv macht. Sobald das Stück identifiziert ist, sollte es eine triviale Aufgabe sein, es zu reparieren. –

+0

Wenn Sie Zugriff auf einen Debugger haben, der über bedingte Haltepunktfunktionen verfügt, würde dies ausreichen. Anderenfalls versuchen Sie, Ihre Sammlung in zwei Hälften zu zerlegen und zu testen, ob das gleiche Problem auftritt. Erhöhen Sie Ihre Sammlung um die Hälfte der verbleibenden Elemente, bis Sie das Problem sehen. Meine gute Reaktion wäre, dass irgendwo auf dem Weg der Aktien-Allokator damit beauftragt wird, die Kapazität Ihrer Sammlung durch das Verdoppeln der derzeitigen Kapazität zu erhöhen, und dass kein zusammenhängender Speicher für die Zuweisung mehr verfügbar ist. –

+0

Der Code wird auf der Kundenseite in der QA-Umgebung ausgeführt. Ich kann auf die Ergebnisse dieses Laufs (Protokolldateien) zugreifen, aber ich kann nicht verlangen, dass sie es in einem Debugger ausführen. –

0

Sie können Ihren eigenen allocator-Typ an std::vector liefern, um die Zuordnung zu verfolgen. Aber ich bezweifle, dass das der Grund ist. Zuerst schaue ich auf die Größen (30-80GB) Ich schließe, es ist ein 64-Bit-Code. Wie könnte ein 32-Bit-negativer Integer-Wert es zur Vektorgröße machen, die 64-Bit ist, wäre es zuerst auf 64-Bit hochgestuft worden, um den Wert zu erhalten? Zweitens, wenn dieses Problem nur unter Solaris auftritt, kann dies auf ein anderes Problem hinweisen. Soweit ich mich erinnere, ist Solaris das einzige Betriebssystem, das Speicher bei der Zuweisung festschreibt, die anderen Betriebssysteme markieren nur den zugewiesenen Adressraum, bis diese Speicherseiten tatsächlich verwendet werden. Also würde ich nach ungenutzten Zuweisungen suchen.

+0

Wie konnte ein negativer 32-Bit-Wert es zu einer Vektorgröße machen? Etwas wie dieses: 'uint32_t count = (uint32_t) GetNumberOfThings(); std :: vectordings (Thing(), count); 'wenn' GetNumberOfThings' bei einem Fehler -1 zurückgibt. Und ja, die vorhandene Codebasis verwendet viele 32-Bit-Größe Variablen und verfügt sogar über eine benutzerdefinierte Vektorimplementierung mit 32-Bit-Größe. Das Problem besteht darin, den fehlerhaften Teil des Codes aufzuspüren ... –