我在Win32项目中使用Delphi 5(安装了FastMM),并且最近一直在尝试大幅减少此应用程序中的内存使用量.到目前为止,我已将使用量减少了近一半,但在处理单独的任务时发现了一些问题.当我最小化应用程序时,内存使用量从45兆位缩减到1兆位,这归功于它分页到磁盘.当我恢复并重新开始工作时,内存仅增加到15兆.当我继续工作时,内存使用量再次缓慢上升,最小化和恢复将其恢复到15兆.所以我的想法是,当我的代码告诉系统释放内存时,根据Windows仍然保留它,实际的垃圾收集直到很久以后才开始.
任何人都可以确认/否认这种行为吗?是否有可能以编程方式清理内存?如果我继续使用该程序而不执行此手动刷新,我会在一段时间后出现内存不足错误,并希望消除它.谢谢.
编辑:我在about.com上发现了一篇文章,其中提供了很多内容以及其他内存管理领域的链接和数据.
我正在使用Delphi 2009,它内置了FastMM4内存管理器.
我的程序读入并处理大型数据集.每当我清除数据集或退出程序时,都会正确释放所有内存.它根本没有内存泄漏.
使用spenwarr答案中给出的CurrentMemoryUsage例程:如何获取Delphi程序使用的内存,我已经显示了FastMM4在处理过程中使用的内存.
似乎正在发生的事情是,在每个进程和发布周期之后,内存的使用正在增长.例如:
在没有数据集的情况下启动程序后使用1,456 KB.
加载大型数据集后使用218,455 KB.
完全清除数据集后,为71,994 KB.如果我在此时退出(或我示例中的任何一点),则不会报告内存泄漏.
再次加载相同的数据集后使用271,905 KB.
完全清除数据集后为125,443 KB.
再次加载相同的数据集后使用325,519 KB.
完全清除数据集后179,059 KB.
再次加载相同的数据集后使用378,752 KB.
在每个加载/清除周期中,我的程序的内存使用量似乎增加了大约53,400 KB.任务管理器确认这确实发生了.
我听说当释放对象时,FastMM4并不总是将所有程序的内存释放回操作系统,以便在需要更多时可以保留一些内存.但这种不断增长使我感到困扰.由于没有报告内存泄漏,我无法确定问题.
有谁知道为什么会这样,如果它是坏的,如果有什么我可以或应该做些什么呢?
谢谢dthorpe和Mason的回答.你让我思考并尝试让我意识到自己错过了什么的事情.因此需要进行详细的调试.
事实证明,我的所有结构在退出时都被正确释放.但是在运行期间每个循环后的内存释放不是.它正在累积内存块,如果我的退出清理不正确,通常会导致泄漏,如果我的退出清理不正确则会在退出时检测到 - 但事实确实如此.
我需要在循环之间清除一些StringLists和其他结构.我仍然不确定我的程序如何正常工作,还有早期周期中的额外数据,但确实如此.我可能会进一步研究.
这个问题已得到解答.谢谢你的帮助.
考虑下一个示例应用程序
program TestMemory;
{$APPTYPE CONSOLE}
uses
PsAPI,
Windows,
SysUtils;
function GetUsedMemoryFastMem: cardinal;
var
st: TMemoryManagerState;
sb: TSmallBlockTypeState;
begin
GetMemoryManagerState(st);
result := st.TotalAllocatedMediumBlockSize + st.TotalAllocatedLargeBlockSize;
for sb in st.SmallBlockTypeStates do
begin
result := result + sb.UseableBlockSize * sb.AllocatedBlockCount;
end;
end;
function GetUsedMemoryWindows: longint;
var
ProcessMemoryCounters: TProcessMemoryCounters;
begin
Result:=0;
ProcessMemoryCounters.cb := SizeOf(TProcessMemoryCounters);
if GetProcessMemoryInfo(GetCurrentProcess(), @ProcessMemoryCounters, ProcessMemoryCounters.cb) then
Result:= ProcessMemoryCounters.WorkingSetSize
else
RaiseLastOSError;
end;
procedure Test;
const
Size = 1024*1024;
var
P : Pointer;
begin
GetMem(P,Size);
Writeln('Inside');
Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem));
Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows));
Writeln(''); …Run Code Online (Sandbox Code Playgroud) 我有一个名为MyForm的表单存储在一个名为Unit UnitMyFrom的单元中.当然Delphi自动添加了这段代码:
TYPE
TMyForm = class(TForm)
private
public
end;
var MyForm: TMyForm;
Run Code Online (Sandbox Code Playgroud)
但我删除了该单位的var声明.有人说这可能会导致IDE出现问题.这是真的吗?IDE是否需要该变量?
编辑:
MyForm不会自动创建.用户在运行时创建该表单.
在最近的帖子中(我的程序永远不会释放内存.为什么?)我表明在使用FastMM时,应用程序不会释放大量内存回系统.最近我创建了一个人工测试程序,以确保它不是一个内存的问题,它只出现在FastMM中.
在这个程序中,我创建并销毁一个对象(与前一篇文章中使用的对象相同)500次.
内存要求是("私人工作集"):
没有FastMM
在运行循环之前:1.2MB
运行循环后:2.1MB
使用FastMM(激进的调试模式)
在运行循环之前:2.1MB
运行循环后:25MB
使用FastMM(发布模式)
运行循环之前:1.8MB
运行循环后:3MB
如果我多次运行循环,则内存要求不会增加.这意味着重用未释放的内存,因此这不是内存泄漏(内存泄漏会增加内存占用,每次运行时会有几KB/MB).
我的问题是:
如何在FastMM中禁用此行为?它甚至可能吗?我知道,如果我在没有FastMM或FastMM Release Mode的情况下发布程序,它将"浪费"适量的RAM.但是,根据需要禁用此行为,将帮助我(我们?)识别内存泄漏.实际上在我的第一篇文章中(见链接),很多人都认为我有泄漏.由于这种行为,显然造成了混乱.不,很明显没有泄漏.只是内存管理器拒绝释放大量内存.
它会释放额外的内存吗?什么时候?什么引发了这个?程序员可以触发吗?例如,当我知道我已经完成了RAM密集型任务并且用户可能暂时不使用该程序(最小化它)时,我可以将RAM刷回系统吗?当用户打开我的程序的多个实例时会发生什么?他们不会争夺内存吗?
在之前的帖子中(我的程序永远不会释放内存.为什么?)我表明FastMM可以缓存(读取为自身保持)相当大的内存.如果您的应用程序刚刚在RAM中加载了大量数据集,则在释放数据后,您将看到令人印象深刻的RAM未释放回内存池.
我环顾四周,似乎调用SetProcessWorkingSetSize API函数会将缓存"刷新"到磁盘.但是,我无法决定何时调用此函数.我想在执行RAM密集型操作的按钮上的OnClick事件结束时调用它.但是,有些人说这可能会导致AV.
如果有人成功使用此功能,请告诉我(我们).
非常感谢.
编辑:
1.释放数据集后,程序仍然需要大量的RAM.调用SetProcessWorkingSetSize后,大小返回到几MB.有人争辩说什么都没有被释放.我同意.但是内存占用现在很小,并且在正常使用程序后不会增加(例如,在执行不涉及加载大型数据集的正常操作时).不幸的是,没有办法证明交换到磁盘的内存被装回内存,但我认为不是.2.我已经证明了(我希望)这不是内存泄漏:
我的程序永远不会释放内存.为什么?
如何说服内存管理器释放未使用的内存