2012-04-04 10 views
1

Ich arbeite an einem Speicher-Scanner, aber der Scan ist so langsam .. kann jemand helfen-ich verbessere es?Speicherscanner mit einem langsamen Scan

procedure FirstScan(scantype, scanvalue: string); 
var 
value :integer; 
dwEndAddr : dword; 
i:dword; 
mbi : TMemoryBasicInformation; 
begin 
    while (VirtualQuery(Pointer(DWORD(mbi.BaseAddress) + MBI.RegionSize), MBI, SizeOf(MEMORY_BASIC_INFORMATION))=SizeOf(TMemoryBasicInformation)) do begin 
    if (MBI.State = MEM_COMMIT) and (MBI.Protect = PAGE_READWRITE) then begin 
    dwEndAddr := DWORD(mbi.BaseAddress) + MBI.RegionSize; 
    for i := DWORD(MBI.BaseAddress) to (dwEndAddr - 1 - sizeof(DWORD)) do begin 
     Application.ProcessMessages; 
     try 
     if scantype = '1 Byte' then begin 
     value := PBYTE(i)^; 
     if scanvalue = IntToStr(value) then ListBox1.Items.Add(IntToHex(i,8)); 
     end; 
     //others scantypes here... 
     except 
     Break; 
     end; 
    end; 
    end; 
    end; 
end; 

Ich habe gelernt, dass ich die Speicherung im Speicher und tun Operationen darauf 4096 Byte Seiten auf einmal lesen müssen dann, bis ich eine neue Seite dann eine weitere 4096 Byte Seite ...

erhalten müssen

Aber ich weiß nicht, wie kann ich das tun ...

Kann jemand helfen-mir? Der Code kann in C oder C++ sein ...

+3

Wenn Ihre Frage wirklich nur ist "Warum ist dieser spezifische Code langsam?" Dann sollten Sie es stattdessen zu http://codereview.stackexchange.com bringen, da Ihre Frage zu lokal ist, um hier auf Stack Overflow von allgemeinem Interesse zu sein. Aber wenn deine Frage nur allgemein lautet: "Wie mache ich willkürlichen langsamen Code schneller?" dann solltest du das stattdessen direkt fragen. –

+0

mbi.BaseAddress und MBI.RegionSize sind beim Eintrag in VirtualQuery() - nicht initialisierte Stapeldaten nicht definiert. –

Antwort

8

Um langsamen Code schnell zu machen, gibt es ein paar Dinge, die Sie tun können. Stellen Sie zunächst sicher, dass der Code richtig ist. Falsche Ergebnisse sind immer noch falsche Ergebnisse, auch wenn Sie sie schnell erhalten. Stellen Sie zu diesem Zweck sicher, dass Sie beim Aufruf von VirtualQuery gültige Werte für alle Parameter übergeben. Am Anfang dieser Funktion ist mbi nicht initialisiert, so dass das Ergebnis von DWORD(mbi.BaseAddress) + MBI.RegionSize Wer-weiß-was ist.

Sobald Sie richtig Code gearbeitet haben, gibt es zwei Möglichkeiten, um es schneller zu machen:

  1. die langsamen Teile finden und sie schnell zu machen. Um dies richtig zu machen, benötigen Sie einen Profiler. Ein Profiler wird Ihr Programm während der Ausführung beobachten und Ihnen dann sagen, wie viel Zeit Ihr Programm für die Ausführung der einzelnen Teile aufgewendet hat. Das sagt dir, wo du dich konzentrieren musst.

  2. ersetzen langsam Algorithmen mit schnellen Algorithmen. Dies kann bedeuten, dass die gesamte Funktion weggeworfen wird oder dass nur bestimmte Teile des Codes repariert werden.

Zum Beispiel könnte Profilierung zeigen, dass Sie viel Zeit Anruf ProcessMessages verbringen. Sie können diese Funktion nicht wirklich schneller machen, da es Teil der VCL ist, aber Sie können es weniger oft nennen. Möglicherweise stellen Sie sogar fest, dass Sie die Nachricht gar nicht aufrufen müssen, wenn erwartet wird, dass der Thread, mit dem Sie diesen Code ausführen, keine Nachrichten empfängt, die verarbeitet werden müssen.

Die Profilerstellung zeigt möglicherweise, dass Sie viel Zeit mit Zeichenfolgenvergleichen verbringen. Wenn die Ihrer Zeichenfolgen häufig gleich sind und sich normalerweise nur am Ende unterscheiden, dann möchten Sie möglicherweise Ihren Zeichenfolgenvergleichsalgorithmus ändern, um Strings mit dem letzten Zeichen statt mit dem ersten zu vergleichen.

Die Profilerstellung zeigt möglicherweise, dass Sie viel Zeit damit verbringen, ganze Zahlen in Zeichenfolgen umzuwandeln, bevor Sie sie vergleichen. Die meisten Programmiersprachen unterstützen den direkten Vergleich von Ganzzahlen. Anstatt einen String-Vergleichsalgorithmus zu verwenden, können Sie stattdessen einen ganzzahligen Vergleichsalgorithmus verwenden. Sie könnten scanvalue in eine Ganzzahl mit StrToInt(scanvalue) konvertieren und direkt mit value vergleichen.

Die Profilerstellung zeigt möglicherweise an, dass Sie wiederholt dasselbe Ergebnis von derselben Eingabe berechnen. Wenn ein Wert sich über einen Teil eines Programms nicht ändert, ändern sich auch die daraus berechneten Werte nicht. Sie können die Kosten für das Konvertieren von Werten reduzieren, indem Sie dies nur tun, wenn sich ein Wert geändert hat. Wenn Sie beispielsweise Ganzzahlvergleiche durchführen, werden Sie wahrscheinlich feststellen, dass sich die Ganzzahlversion von scanvalue in Ihrer Funktion nicht ändert. Sie könnten scanvalue einmal zu Beginn der Funktion in eine Ganzzahl umwandeln und dann value mit der innerhalb der Schleife vergleichen, anstatt StrToInt(scanvalue) oft aufzurufen.

+0

Danke, ich werde diese Fehler beheben und zurück hier, um die Ergebnisse zu veröffentlichen. – paulohr

+0

Frage bearbeitet, können Sie es jetzt sehen? – paulohr

+0

Natürlich kann ich die Veränderung sehen. Aber ich habe Sie abgelehnt, weil Sie die gesamte Frage geändert haben und die Antworten, die Sie auf die ursprüngliche Frage erhalten haben, vollständig ungültig gemacht haben. –

10

ich Ihnen ein wenig helfen kann ... dass Application.ProcessMessages aus der inneren Schleife bekommen. Du rufst es für jeden an. Single. Byte. Sie. Scan. Sie müssen nicht ganz , dass reagiert auf Fenster Nachrichten sein. :)

verschiebe es in die äußere Schleife, und Sie sollten eine deutliche Geschwindigkeitssteigerung sehen. Ich würde sagen, einen Thread spawnen und Application.ProcessMessages insgesamt loswerden, da es wirklich nicht die Aufgabe dieses Codes ist, aber ich bin nicht sicher, wie/ob Delphi Threads tut.

auch .... Sie vorbei an den Scan-params als Strings? Wenn Sie darauf bestehen, legen Sie vor dem Start der Schleife, die den zu verwendenden Suchtyp angibt, einen Wert für int oder enum oder etwas fest, konvertieren Sie den Wert in einen nützlichen Typ für Ihre Suche und vergleichen Sie ihn. Zeichenfolgenvergleiche sind in der Regel langsamer als Ganzzahlvergleiche, insbesondere wenn Sie jedes Mal neue Zeichenfolgen erstellen.

+0

Es ist alles ein Haufen der vollständigen Entfernung von Application.Processmessages. Das Abfädeln sollte in Delphi ziemlich einfach sein. –

1

Auch: Sie konvertieren den aktuellen Zeiger in eine Zeichenfolge für jedes Byte Sie zugreifen. Yech, schrecklich langsam. Ändern Sie stattdessen zu Beginn Ihrer Prozedur scanvalue in ein BYTE und führen Sie den Vergleich direkt auf BYTEs durch. = DWORD (MBI.BaseAddress) Loop: -

Schließlich wird die "if scantype = '1 Byte'" aus dem für i ziehen. Sie wollen nicht für jedes Byte, dass „wenn“ Anweisung zu tun - stattdessen tun

if scantype = '1 byte' then 
    for i:= DWORD(...) 
else if scantype='other scan type' then... 

und so weiter. (Und ja, sollten Sie konvertieren, dass „wenn scantype“ Vergleich zu einem Enum oder Dingsbums.)

+0

Gut, danke! – paulohr