【问题标题】:How can I find out how much memory is used by a specific component or class?如何找出特定组件或类使用了多少内存?
【发布时间】:2013-03-15 09:15:28
【问题描述】:

是否可以在delphi中检索单个组件使用的内存量?

我正在从 Internet 下载简单的字符串,我发现在下载过程结束时内存使用量高达 1 GB,但是当我查看包含我下载的所有内容的保存文件时,只有在千字节范围内,显然组件发生了一些事情,即使我销毁了它们。

例子:

编辑:

procedure TForm1.OnCreate(Sender: TObject);
  var list: TStringList;
begin
  list:=TStringList.Create;
  list.LoadFromFile('10MB_of_Data.txt');
  list.destroy;
end;

我如何知道作为 TStringList 的“列表”正在使用 10 MB 的内存空间?

谢谢。

【问题讨论】:

  • 我猜您想要此信息用于调试目的? (看起来该组件确实存在一些内存问题......)我猜你已经知道诸如全局 ReportMemoryLeaksOnShutdown 变量之类的东西?
  • 有趣,如何开启?
  • Ken:“InstanceSize 不是你想要的”,Xaid:“我试过 InstanceSize,但它不是我想要的。”
  • 请展示一个完整的程序。否则只会导致徒劳的猜测。
  • 如果我对情况的理解正确,您有一个错误的组件会泄漏内存。如果您是组件的作者,或者您可以访问源代码,则应该尝试修复它。否则,如果可能,您应该联系开发人员。

标签: delphi memory components


【解决方案1】:

我认为比较之前和之后的内存使用情况是解决这个问题的方法,因为没有简单的方法可以查看事后代码块分配了哪些内存......例如,上面的字符串列表,类本身只会占用少量内存,因为它由指向其他分配的指针(即字符串数组)组成,并且它本身是指向实际字符串的指针数组......这是一个比较简单的案例。

无论如何,这可以使用 FastMM 来完成,其功能如下...

uses
  FastMM4;

function CheckAllocationBy(const AProc: TProc): NativeUInt;
var
  lOriginalAllocated: NativeUInt;
  lFinalAllocated: NativeUInt;
  lUsage: TMemoryManagerUsageSummary;
begin
  GetMemoryManagerUsageSummary(lUsage);
  lOriginalAllocated := lUsage.AllocatedBytes;
  try
    AProc;
  finally
    GetMemoryManagerUsageSummary(lUsage);
    lFinalAllocated := lUsage.AllocatedBytes;
  end;
  Result := lFinalAllocated - lOriginalAllocated;
end;

而且可以这样使用...

lAllocatedBytes := CheckAllocationBy(
  procedure
  begin
    list:=TStringList.Create;
    list.LoadFromFile('10MB_of_Data.txt');
    list.Free;
  end);

这会告诉你你的字符串列表留下了多少(有趣的是,我在第一次重复调用时得到 40 个字节,在调用前后查阅使用日志后得到 0 个字节是在第一次打电话)。如果您想检查泄漏内存的分配位置,使用 FastMM 也很简单(尽管我同意上述观点,如果它是第 3 方,那应该不是您的问题)。

【讨论】:

  • 是的,比较似乎是最好的方法。谢谢!
  • 似乎合法,但在多线程环境中,当另一个线程也可能同时增加内存消耗时,这将如何工作?
  • 简单地说......它不会。如果调试,可能会在初始使用检查之前冻结其他线程以确保(如果需要该级别的保证)......尽管这可能会导致锁定。此外,它可能是另一个线程代表被测代码分配出血内存。关键是我们只是不知道组件的内部工作原理。
  • 只是另一个想法。在考虑包装库的组件时可能会变得更糟(例如 TPerlRegEx 可以吗?)。我认为在这个库中分配的内存也不会从本地内存管理器中看到......尽管它会耗尽进程可用的内存。那好吧。更多值得深思的地方。
【解决方案2】:

首先:请耐心等待,这实际上并不能完全回答您的问题,但它太大了,无法在评论中发布。此代码是使用 FPC 编写和编译的,但它可以为您提供一些估计。可能有人知道如何将它移植到 Delphi。

program project4;

uses
    SysUtils,
    Classes;

var
    p: Pointer;
    sl: TStringList;
var
    a: TFPCHeapStatus;
begin
    a := GetFPCHeapStatus;
    writeln('== 1 ==');
    //writeln(a.MaxHeapSize);
    writeln(a.MaxHeapUsed);
    //writeln(a.CurrHeapSize);
    writeln(a.CurrHeapUsed);
    //writeln(a.CurrHeapFree);

    GetMem(p, 1024);

    a := GetFPCHeapStatus;
    writeln('== 2 ==');
    writeln(a.MaxHeapUsed);
    writeln(a.CurrHeapUsed);

    sl := TStringList.Create;

    a := GetFPCHeapStatus;
    writeln('== 3 ==');
    writeln(a.MaxHeapUsed);
    writeln(a.CurrHeapUsed);

    sl.Add('To beer or not to beer? That is the question!');

    a := GetFPCHeapStatus;
    writeln('== 4 ==');
    writeln(a.MaxHeapUsed);
    writeln(a.CurrHeapUsed);

    Readln;
end.

和输出:

== 1 ==
2448
2448
== 2 ==
3488
3488
== 3 ==
3568
3568
== 4 ==
3616
3616

还有一个大文本文件的测试:

sl.LoadFromFile('tolstoy - war and peace.txt');

a := GetFPCHeapStatus;
writeln('== 4 ==');
writeln(a.MaxHeapUsed);
writeln(a.CurrHeapUsed);  

输出:

== 3 ==
3568
3568
== 4 ==
8837104
4643776

文件大小:3.1 Mb(3 280 005 字节)(ansi 编码)

【讨论】:

  • 这没有回答所提出的问题,即“特定组件使用多少内存?”以向字符串列表添加一些 10M 字符串为例。您创建了一个空字符串列表,然后添加了一个已知长度的字符串。请使用该信息来预测如果将 10M 随机长度的字符串添加到字符串列表将占用多少内存。 (不是相同长度的字符串 - 随机长度的字符串。)
  • == 3 == 3568 3568 == 4 == 8837104 4643776 文件“tolstoy - 战争与和平.txt”,ansi 编码,大小 = 3,1 Mb。
  • 那不是10M的随机字符串;这是一组固定大小(3.1Mb)的数据。现在对 1M 组其他数据重复 1M 次,并告诉我 TStringList 的大小。正如我在对原始帖子的评论中所说,您不能这样做,因为您现在需要了解有关它包含的数据的信息。阅读原始问题的意图,以及对其提出的问题。
  • @KenWhite 看来我们彼此不理解 :) 我的测试文本文件是 49839 个“随机”字符串集(原谅我,Leo Tolstoy!)我只是没有任何其他文本文件具有适当的大小(除了不能加载到 32 位应用程序中的大约 3 Gb 的 DB 转储)。或者你的意思是for i := 0 to 1000000 do begin sl.LoadFromFile('file' + IntToStr(i)); {test memory} end;
  • @DavidHeffernan 问题是:“是否可以检索 delphi 中单个组件使用的内存量?”在我上面的评论中,有几种可能的解决方案之一:比较使用的内存“之前”和“之后”。我刚刚发布了用 FP 编写的示例(不幸的是,我有一段时间没有使用 Delphi)。
猜你喜欢
  • 1970-01-01
  • 2011-05-06
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-10
  • 2010-12-05
  • 1970-01-01
相关资源
最近更新 更多