我可以测量线程的实际内存使用量吗?

时间:2014-03-11 18:14:04

标签: multithreading delphi memory

如果是,我会很感激Delphi中的一个例子。

我已尝试使用TMemoryManagerStateGetProcessMemoryInfo

3 个答案:

答案 0 :(得分:10)

线程本身不使用内存。进程拥有线程之间共享的内存。内存可以并且通常在一个线程中分配并在另一个线程中使用。所以你问的问题是不明确的。

那就是说,你当然可以跟踪特定线程的分配和解除分配。您可以安装一个跟踪堆分配的内存管理器,并存储在线程ID索引的字典中分配的字节数。

使用GetMemoryManagerSetMemoryManager将分配计数内存管理器注入运行时。想法是通过调用GetMemoryManager来记录原始内存管理器。然后使用SetMemoryManager替换注入内存管理器。您的内存管理器跟踪分配,并将实际分配委派给原始内存管理器。

答案 1 :(得分:9)

在Delphi中,使用Delphi的标准内存管理器(FastMM),这是不可能的。 FastMM并不关心分配哪个线程内存。

其他一些内存管理器可能提供此功能。

答案 2 :(得分:3)

看起来您可以使用ScaleMM(https://code.google.com/p/scalemm/)跟踪内存,因为它通过线程分配内存。开箱即用,它没有你需要的东西,但有些地方你可以添加它。

如果我查看代码,您可以在需要获取分配的内存量时自行遍历内存列表,或者挂钩到TThreadMemManager.GetMem,TThreadMemManager.FreeMem和TThreadMemManager.FreeMemFromOtherThread调用。此代码位于ScaleMM2.pas文件中。将记忆库添加到TThreadMemManager应该很容易,因为每个线程已经存在一个。对于另一种选择,我会查看TMediumThreadManager.ReleaseAllFreeMem中的代码,以了解它如何遍历列表。您可以执行类似的操作,并在任何时间点获取已分配RAM的列表。

要小心这一点,因为像块大小和碎片这样的东西可能意味着你会得到误导性的结果。

以下是ScaleMM2的一些更改,它们将返回每个线程的内存使用情况:

我在TThreadMemManager中添加了一个名为TotalAllocated的变量:

  FSmallMemManager : TSmallMemThreadManager;
  FMediumMemManager: TMediumThreadManager;
  FLargeMemManager : TLargeMemThreadManager;
  FTotalAllocated: Int64;
protected

然后我将以下两行添加到FreeMem的底部:

  {$IFDEF SCALEMM_DEBUG}
  CheckMem(nil);
  {$ENDIF}
  FTotalAllocated := FTotalAllocated + pm.Size;
end;

和GetMem:

  {$IFDEF SCALEMM_DEBUG}
  CheckMem(nil);
  {$ENDIF}
  FTotalAllocated := FTotalAllocated + aSize;
end;

我创建了一个名为FThreadManagerList的全局列表:

FThreadManagerList: TList<PThreadMemManager>

然后在我要检查的线程的开头,我添加了以下代码:

var
  threadManager: PThreadMemManager;
begin
  threadManager := GetThreadMemManager;
  Synchronize(
    procedure
    begin
      FThreadManagerList.Add(threadManager);
    end);

之后,获取线程的内存就像这样简单:

for I := 0 to FThreadManagerList.Count - 1 do
begin
  ListBox1.Items.Add(IntToStr(FThreadManagerList[I].FThreadID)+' : '+IntToStr(FThreadManagerList[I].FTotalAllocated));
end;

我没有查看交叉线程分配,您需要做一些研究,看看它们是如何工作的。我也没有寻找任何竞争条件,但我不认为这将是一个问题,除非你的一个线程退出。它应该给你一些东西。