【问题标题】:Memory scanner with a slow scan扫描速度慢的内存扫描仪
【发布时间】:2012-04-04 16:41:42
【问题描述】:

我正在使用内存扫描仪,但扫描速度太慢了.. 谁能帮我改进一下?

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++...

【问题讨论】:

  • 如果您的问题真的只是“为什么这个特定的代码很慢?”那么您应该将其带到codereview.stackexchange.com,因为您的问题过于本地化,无法在 Stack Overflow 上引起普遍关注。但是,如果您的问题通常只是“如何使任意慢代码更快?”那么你应该直接问这个。
  • mbi.BaseAddress 和 MBI.RegionSize 在进入 VirtualQuery() 时未定义 - 未初始化的堆栈数据。

标签: c++ c delphi memory


【解决方案1】:

我可以帮你一点...把Application.ProcessMessages 从内部循环中解脱出来。你在为每个人打电话。单身的。字节。你。扫描。您不需要对窗口消息非常那样响应。 :)

将其移至外循环,您应该会看到速度显着提高。我会说产生一个线程并完全摆脱Application.ProcessMessages,因为这真的不是这段代码的工作,但我不确定Delphi如何/是否处理线程。

另外....您将扫描参数作为字符串传递?如果您坚持这样做,请在开始循环说明要使用的扫描类型之前设置一个 int 或 enum 或其他内容,将值转换为对您的搜索有用的类型,然后进行比较。字符串比较往往比整数比较慢,尤其是当您每次都创建新字符串时。

【讨论】:

  • 都是一堆完全删除Application.Processmessages。在 Delphi 中线程化应该相当容易。
【解决方案2】:

要使慢速代码变快,您可以做一些事情。首先,确保您的代码正确。错误的结果仍然是错误的结果,即使你很快得到它们。为此,请确保当您调用VirtualQuery 时,您为所有参数传递了有效值。在这个函数的开始处,mbi 是未初始化的,所以DWORD(mbi.BaseAddress) + MBI.RegionSize 的结果将是who-knows-what。

一旦你的代码可以正常工作,有两种方法可以让它更快:

  1. 找到慢的部分,让它们变快。要做到这一点,您需要一个分析器。分析器将在您的程序运行时观察它,然后告诉您程序执行每个部分所花费的时间百分比。这告诉你应该把精力集中在哪里。

  2. 用更快的算法替换慢速算法。这可能意味着丢弃整个函数,也可能意味着只修复代码的某些部分。

例如,分析可能显示您花费大量时间致电ProcessMessages。由于它是 VCL 的一部分,因此您无法真正使该函数更快,但您可以不经常调用它。如果您正在运行此代码的线程预计不会收到任何需要处理的消息,您甚至可能会发现根本不需要调用它。

分析可能表明您花费大量时间进行字符串比较。如果您的字符串的 开始 经常相等,并且通常只在结尾有所不同,那么您可能希望更改字符串比较算法以从最后一个字符而不是第一个字符开始比较字符串。

分析可能表明您在比较整数之前花费了大量时间将它们转换为字符串。大多数编程语言都支持直接比较整数,因此您可以尝试使用整数比较算法,而不是使用字符串比较算法。您可以使用StrToInt(scanvalue)scanvalue 转换为整数,然后直接与value 进行比较。

分析可能表明您正在从相同的输入重复计算相同的结果。如果一个值在程序的某些部分没有改变,那么从它计算的值也不会改变。您可以通过仅在值发生更改时进行转换来降低转换值的成本。例如,如果您进行整数比较,那么您可能会发现 scanvalue 的整数版本在您的函数中没有改变。您可以在函数开始时将scanvalue 转换为整数一次,然后将value 与循环内的值进行比较,而不是多次调用StrToInt(scanvalue)

【讨论】:

  • 谢谢,我会修正这些错误并返回这里发布结果。
  • 我当然可以看到变化。但是我拒绝了你,因为你改变了整个问题,完全使你对原始问题的答案无效。
【解决方案3】:

另外:您正在将当前指针转换为字符串对于您访问的每个字节。哎呀,慢得可怕。相反,在程序开始时将 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”比较转换为枚举或诸如此类。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多