1

私はメモリ スキャナーに取り組んでいますが、スキャンが非常に遅い..誰か助けてくれますか?

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;

一度に 4096 バイトのページを読み取り、それらをメモリに保存して操作を行う必要があることを学びました。新しいページが必要になるまで、別の 4096 バイトのページを取得します...

しかし、私はそれをどのように行うことができるのかわかりません...

誰か助けてくれませんか?コードは C または C++ で記述できます...

4

3 に答える 3

10

私はあなたを少し助けることができます...それをApplication.ProcessMessages内側のループから抜け出させてください。あなたはすべてのためにそれを呼んでいます。独身。バイト。あなた。スキャン。ウィンドウ メッセージにそれほど敏感ある必要はありません。:)

外側のループに移動すると、速度が大幅に向上するはずです。実際にはこのコードが処理する仕事ではないので、スレッドを生成して完全に取り除くと思いますが、Application.ProcessMessagesDelphi がどのように/スレッドを実行するかはわかりません。

また....スキャンパラメータを文字列として渡していますか?そうしなければならない場合は、使用するスキャン タイプを示すループを開始する前に int や enum などを設定し、その値を検索に役立つタイプに変換して比較します。文字列の比較は、特に毎回新しい文字列を作成する場合、整数の比較よりも遅くなる傾向があります。

于 2012-04-04T16:47:51.660 に答える
8

遅いコードを速くするためにできることがいくつかあります。まず、コードが正しいことを確認してください。間違った結果は、すぐに得られたとしても、依然として間違った結果です。そのためには、 を呼び出すときにVirtualQuery、すべてのパラメーターに有効な値を渡していることを確認してください。この関数の開始時点でmbiは初期化されていないため、 の結果はDWORD(mbi.BaseAddress) + MBI.RegionSize誰が知っているかになります。

正しく動作するコードを作成したら、それを高速化する方法が 2 つあります。

  1. 遅い部分を見つけて速くします。これを正しく行うには、プロファイラーが必要です。プロファイラーはプログラムの実行を観察し、プログラムが各部分の実行に費やした時間の割合を示します。それはあなたの努力をどこに向けるべきかを教えてくれます。

  2. 遅いアルゴリズムをより高速なアルゴリズムに置き換えます。これは、関数全体を破棄することを意味する場合もあれば、コードの特定の部分だけを修正することを意味する場合もあります。

たとえば、プロファイリングにより、通話に多くの時間を費やしていることがわかる場合がありますProcessMessages。その関数は VCL の一部であるため、これ以上高速化することはできませんが、呼び出す頻度を減らすことはできます。このコードを実行しているスレッドが、処理が必要なメッセージを受信することが想定されていない場合は、まったく呼び出す必要がないことに気付くかもしれません。

プロファイリングにより、文字列の比較に多くの時間を費やしていることがわかる場合があります。文字列の先頭が頻繁に同じで、通常は最後だけが異なる場合は、文字列比較アルゴリズムを変更して、最初の文字ではなく最後の文字から文字列の比較を開始することをお勧めします。

プロファイリングは、整数を比較する前に、整数を文字列に変換するのに多くの時間を費やしていることを示す場合があります。ほとんどのプログラミング言語は整数の直接比較をサポートしているため、文字列比較アルゴリズムを使用する代わりに、整数比較アルゴリズムを使用してみることができます。scanvalueで整数に変換し、StrToInt(scanvalue)と直接比較できvalueます。

プロファイリングは、同じ入力から同じ結果を繰り返し計算していることを示す場合があります。プログラムのある部分で値が変化しない場合、そこから計算される値も変化しません。値が変更された場合にのみ変換を行うことで、値の変換のコストを削減できます。たとえば、整数の比較を行う場合、おそらく、関数内で の整数バージョンがscanvalue変更されないことがわかります。scanvalue関数の開始時に一度整数に変換し、何度もvalue呼び出す代わりにループ内でそれと比較することができStrToInt(scanvalue)ます。

于 2012-04-04T17:39:07.243 に答える
1

また、現在のポインターを、アクセスするすべてのバイトの文字列に変換しています。うん、恐ろしく遅い。代わりに、手順の開始時に scanvalue を BYTE に変更し、BYTE で直接比較を行います。

最後に -- 「if scantype = '1 byte'」を for i:=DWORD(MBI.BaseAddress) ループから引き出します。すべてのバイトに対してその「if」ステートメントを実行したくない-代わりに、実行します

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

等々。(そして、はい、その「if scantype」比較を列挙型などに変換する必要があります。)

于 2012-04-04T17:30:27.267 に答える