gpt4 book ai didi

delphi - Delphi 中对象的字符串共享/引用问题

转载 作者:行者123 更新时间:2023-12-03 15:28:03 25 4
gpt4 key购买 nike

我的应用程序根据文件名(以及其他基于字符串的信息)在内存中构建许多对象。我希望通过单独存储路径和文件名来优化内存使用,然后在同一路径中的对象之间共享路径。我并没有尝试使用字符串池或任何东西,基本上我的对象是排序的,所以如果我有 10 个具有相同路径的对象,我希望对象 2-10 的路径“指向”对象 1 的路径(例如对象[2].Path=对象[1].Path);

但我有一个问题,在我认为我告诉它们之后(通过对象[2].Path=对象[1]),我不相信我的对象实际上共享对同一字符串的引用。路径分配)。

当我对字符串列表进行实验并将所有值设置为指向列表中的第一个值时,我可以看到“内存保护”正在发挥作用,但是当我使用对象时,我完全看不到任何变化,诚然,我只是使用任务管理器(私有(private)工作集)来观察内存使用变化。

这是一个人为的例子,我希望这是有道理的。

我有一个对象:

TfileObject=class(Tobject)
FpathPart: string;
FfilePart: string;
end;

现在我创建该对象的 1,000,000 个实例,为每个实例使用一个新字符串:

var x: integer;
MyFilePath: string;
fo: TfileObject;
begin
for x := 1 to 1000000 do
begin
// create a new string for every iteration of the loop
MyFilePath:=ExtractFilePath(Application.ExeName);
fo:=TfileObject.Create;
fo.FpathPart:=MyFilePath;
FobjectList.Add(fo);
end;
end;

运行它,任务管理器说我正在使用 68MB 内存或其他东西。 (请注意,如果我在循环外部分配 MyFilePath,那么我确实会节省内存,因为有 1 个字符串实例,但这是一个人为的示例,实际上并不是它在应用程序中发生的情况)。

现在我想通过使所有对象共享路径字符串的相同实例来“优化”内存使用,因为它具有相同的值:

var x:整数; 开始 对于 x:=1 到 FobjectList.Count-1 执行 开始 TfileObject(FobjectList[x]).FpathPart:=TfileObject(FobjectList[0]).FpathPart; 结尾; 结束;

任务管理器显示绝对没有任何变化。

但是,如果我对 TstringList 执行类似的操作:

var x: integer;
begin
for x := 1 to 1000000 do
begin
FstringList.Add(ExtractFilePath(Application.ExeName));
end;
end;

任务管理器显示 60MB 内存使用量。

现在优化:

var x: integer;
begin
for x := 1 to FstringList.Count - 1 do
FstringList[x]:=FstringList[0];
end;

任务管理器显示内存使用量下降了我所期望的,现在为 10MB。

所以我似乎能够在字符串列表中共享字符串,但不能在对象中共享字符串。我显然在概念上、代码中或两者上都遗漏了一些东西!

我希望这是有道理的,我真的可以看到使用这种技术节省内存的能力,因为我有很多对象都包含大量字符串信息,数据以多种不同的方式排序,我希望能够一旦数据加载到内存中,就对其进行迭代,并通过以这种方式共享字符串来再次释放一些内存。

预先感谢您提供的任何帮助。

PS:我使用的是 Delphi 2007,但我刚刚在 Delphi 2010 上进行了测试,结果是相同的,只是 Delphi 2010 由于 unicode 字符串而使用了两倍的内存...

最佳答案

当您的 Delphi 程序分配和释放内存时,它不是直接使用 Windows API 函数,而是通过内存管理器来执行此操作。您在这里观察到的事实是,当程序不再需要内存管理器时,内存管理器不会将所有分配的内存释放回操作系统。它将保留部分或全部分配给以后,以加快应用程序中以后的内存请求。因此,如果您使用系统工具,内存将被列为由程序分配,但它并未处于事件使用状态,它在内部被标记为可用,并存储在可用内存块列表中,MM 将使用这些可用内存块来存储任何其他内存在程序进入操作系统并请求更多内存之前,在程序中进行分配。

如果您想真正检查程序的任何更改如何影响内存消耗,您不应该依赖外部工具,而应该使用内存管理器提供的诊断。下载完整的 FastMM4 版本,并将其作为 DPR 文件中的第一个单元在您的程序中使用。您可以使用GetMemoryManagerState()函数获取详细信息,该函数会告诉您使用了多少小、中、大内存块以及为每个 block 大小分配了多少内存。不过,要进行快速检查(此处完全足够),您只需调用 GetMemoryManagerUsageSummary() 函数即可。它会告诉您分配的总内存,如果您调用它,您将看到您对 FPathPart 的重新分配确实释放了几 MB 内存。

使用 TStringList 时,您将观察到不同的行为,并且所有字符串均按顺序添加。这些字符串的内存将从较大的 block 中分配,并且这些 block 将不包含任何其他内容,因此当释放字符串列表元素时可以再次释放它们。如果您创建对象,那么字符串将与其他数据元素交替分配,因此释放它们将在较大的 block 中创建空内存区域,但这些 block 不会被释放,因为它们仍然包含用于其他内容的有效内存。您基本上增加了内存碎片,这本身可能就是一个问题。

关于delphi - Delphi 中对象的字符串共享/引用问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2439886/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com