我声明全局变量动态数组 A,在释放的时候为什么要先setlength(A,0),然后freeandnil呢,不用freeannil行吗?如果不用freeandnil,会出现情况呢。
我参与的是实时监控项目,需要不断根性数据,也就是说,不断清空哈希表,然后再向里边填充数据,然后在清空。数据每1分钟更新一次,我检查了每个函数和过程,还有全局变量,该释放时候都手动释放了,尤其是局部数组和哈希表等等,我都手动释放,为什么运行一段时间后,程序占用的内存一直再涨啊?TTTTTTTT。
最后我使用了网上一段代码,放到程序当中,隔一段时间运行一次,代码是
procedure TfrmMain.ClearMemory;
begin
if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
application.ProcessMessages;
end;
end;
这段代码是什么意思啊,用到这段代码后,内存瞬间减少很多。但是占用内存大小并不确定,有时候我一直看着,最大不过10M,而且马上就小了。有的时候涨到20M左右,但是不会再明显增加,维持在20M。
如果去掉这段代码,我点击子窗体,然后关闭他,再点击,再关闭,内存一直在涨,关闭之后却没有明显释放内存。我没有在dpr当中创建子窗体,只是在程序中creat(nil),然后,手动在finnaly中free他。看起来,是手动创建,手动释放,但是却一直涨内存,为什么呢YTTTTTTTTTTTTTTTTTTTTTTT
我参与的是实时监控项目,需要不断根性数据,也就是说,不断清空哈希表,然后再向里边填充数据,然后在清空。数据每1分钟更新一次,我检查了每个函数和过程,还有全局变量,该释放时候都手动释放了,尤其是局部数组和哈希表等等,我都手动释放,为什么运行一段时间后,程序占用的内存一直再涨啊?TTTTTTTT。
最后我使用了网上一段代码,放到程序当中,隔一段时间运行一次,代码是
procedure TfrmMain.ClearMemory;
begin
if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
application.ProcessMessages;
end;
end;
这段代码是什么意思啊,用到这段代码后,内存瞬间减少很多。但是占用内存大小并不确定,有时候我一直看着,最大不过10M,而且马上就小了。有的时候涨到20M左右,但是不会再明显增加,维持在20M。
如果去掉这段代码,我点击子窗体,然后关闭他,再点击,再关闭,内存一直在涨,关闭之后却没有明显释放内存。我没有在dpr当中创建子窗体,只是在程序中creat(nil),然后,手动在finnaly中free他。看起来,是手动创建,手动释放,但是却一直涨内存,为什么呢YTTTTTTTTTTTTTTTTTTTTTTT
解决方案 »
- 老师的,但用不好呀.
- 有没有子串在字符串中出现次数的函数
- 使用odac时将net打为true,连接数据库时报错:service unvavilable!如何这是什么原因啊?
- 一个线程建立一个异步的TClientSocket对象,发现不能触发OnConnect等任何事件,什么原因呢?
- 在这里有些问题需要用图像来表达,应当如何作??
- 如何让fastreport2.51中的frPrintGrid1打印出来的报表自动居中
- 信封打印问题?象超级信封打印工具专业版 7.0F一样!
- 如何判断一个网站是否支持断点续传(Http)!
- 紧急求助-----怎么做帮助文件?
- 用delphi能不能做这样的软件,阻止某ip通过局域网访问internet?
- 讨论: 如何在 delphi7 + devExpress bar 6 制作的: ribbon 风格程序,体积小一些?
- Porject Project1.exe raised exception class EOleException with mes
begin
if Sender is TMenuItem then
begin
case (Sender as TMenuItem).Tag of
100: begin
with TfrmDeviceExceptQuery.Create(nil) do
try
ShowModal;
finally
Free;
end;
end;
101: begin
try
if Application.MessageBox('确定要退出应急平台系统吗?','系统提示',MB_YESNO or MB_ICONQUESTION) = mrNo then Exit ; MyThread.DoTerminate(); //结束非主线程
Clear_MonitorTable; //避免出现Access violation报警 Application.Terminate;
except
;
end;
END;
102: begin
with TfrmFaultQryCnt.Create(nil) do
try
ShowModal;
finally
Free; end; end;
103: begin
if iRight= -1 then
with TfrmRightLogin.Create(nil) do
try
ShowModal;
finally //根据登录人的信息确认权限,并传入ID和姓名
iRight:= iCheckRight; //登录权限
sAccountID:= sUserID; //把登录人的账号名字传出来,发短信时候要用
Free;
end
else
if iRight<> -1 then
iRight:= -1;
prop_SetMenuDicEnable; //根据权限设置字典菜单是否可用
end;
104: begin
with TfrmSMSSend.Create(nil) do
try
sSenderID:= sAccountID; //将登录人员的信息传到发送短信界面里
ShowModal;
finally
Free;
end; end;
105: begin
with TfrmSMSHistoryQuery.Create(nil) do
try
ShowModal;
finally
Free;
end;
end;
106: begin
with TfrmOxyNitQuery.Create(nil) do
try
ShowModal;
finally
Free;
end;
end;
107: begin
with TfrmDrawnSteel.Create(nil) do
try
ShowModal;
finally
Free;
end; end;
end;
end;
end;
这个是创建子窗体的代码,点击右键菜单,根据每个选项的Tag值判断创建哪个,然后free哪个
手动创建 ,手动释放的。
procedure TfrmMain.GetIndexConfigeration;
var
i : Integer;
sSql : string;
qryTmp: TADOQuery;
begin
sSql:= 'SELECT F_PROCESS_ID,F_INDEX_ID,F_TAG_NAME,F_INDEX_LOWER'
+ ',F_INDEX_UPPER,F_INDEX_CONNECTED,F_INDEX_INTERVENE,F_TIME_CONTINUAL,F_ALERT_TYPE FROM VKIP_DIC_DEVICE_INDEX';
qryTmp:=TPublic.Fnt_OpenSql(dmMain.conOnTime,sSql);
if (glb_IndexConfig= nil) or (Length(glb_IndexConfig)<> qryTmp.recordcount) then
begin
SetLength(glb_IndexConfig,0);
FreeAndNil(glb_IndexConfig);
SetLength(glb_IndexConfig,qryTmp.RecordCount,11);
end; qryTmp.First;
while not qryTmp.Eof do
for i:=0 to qryTmp.recordcount - 1 do
begin
glb_IndexConfig[i,0]:= qryTmp.fieldbyname('F_PROCESS_ID').AsString;
glb_IndexConfig[i,1]:= qryTmp.fieldbyname('F_INDEX_ID').AsString;
glb_IndexConfig[i,2]:= qryTmp.fieldbyname('F_TAG_NAME').AsString;
glb_IndexConfig[i,3]:= qryTmp.fieldbyname('F_INDEX_LOWER').AsString;
if (glb_IndexConfig[i,8]<>'3') and (glb_IndexConfig[i,8]<>'4') then
glb_IndexConfig[i,4]:= qryTmp.fieldbyname('F_INDEX_UPPER').AsString;
glb_IndexConfig[i,5]:= qryTmp.fieldbyname('F_INDEX_CONNECTED').AsString;
glb_IndexConfig[i,6]:= qryTmp.fieldbyname('F_INDEX_INTERVENE').AsString;
glb_IndexConfig[i,7]:= qryTmp.fieldbyname('F_TIME_CONTINUAL').AsString;
glb_IndexConfig[i,8]:= qryTmp.fieldbyname('F_ALERT_TYPE').AsString;
//glb_IndexConfig[i,9]:= ''; //记录本次持续异常的开始时间
glb_IndexConfig[i,10]:= '-1';//记录指标状态 qryTmp.Next;
end;
Freeandnil(qryTmp);
end;
glb_IndexConfig是一个全局变量,数组,如果直接把
SetLength(glb_IndexConfig,0); 注释的话,就报错了
这就是他的类型,二维动态数组。
有时候动态数组占用内存比较大时,想在离开了作用域前释放的(比如一些全局的动态数组变量),赋值为nil就行了
刚才那个清理内存的代码我不用了,看来不好用
其实我每个函数和过程都把能释放的都是放了,比如TADOQUERY还有,哈希表,动态数组等等,结果内存一直在上涨TTTTTTTTTT,总得有个上限吧TTTTTTTTTTT
procedure TfrmMain.GetCurrentData;
var
sSql: string;
qryWeb: TADOQuery;
i: Integer;
begin
if glb_CurrentDataHashed <> nil then
// glb_CurrentDataHashed.Free;
FreeAndNil(glb_CurrentDataHashed);
glb_CurrentDataHashed:=THashedStringList.Create; sSql:= 'SELECT TAGNAME,VALUE FROM V_ANALOGLIVE';
qryWeb:= TPublic.Fnt_OpenSqlWeb(sSql); for i:= 0 to qryWeb.RecordCount -1 do
begin
glb_CurrentDataHashed.Add(qryWeb.FieldByName('TAGNAME').AsString +'=' +qryWeb.fieldbyname('VALUE').AsString);
qryWeb.Next;
end;
// qryWeb.Free;
FreeAndNil(qryWeb);
end;
这个是哈希表和TADOQUERY的释放,不管释放是否啰嗦,我都完全做到释放了吧
TTTT,内存变为16M了,激动啊。
离开作用域自动释放,意思是说机器要判断是否离开了作用域那么释放内存是需要一定的时间了?if (glb_IndexConfig= nil) or (Length(glb_IndexConfig)<> qryTmp.recordcount) then
begin
SetLength(glb_IndexConfig,0);
FreeAndNil(glb_IndexConfig);
SetLength(glb_IndexConfig,qryTmp.RecordCount,11);
end;也就是说,我直接
if (glb_IndexConfig= nil) or (Length(glb_IndexConfig)<> qryTmp.recordcount) then
begin
glb_indexConfig:= nil;
SetLength(glb_IndexConfig,qryTmp.RecordCount,11);
end;
这样可以吗。如果排除代码啰嗦,冗余(多余),原来的代码是不是也没有错误呢
procedure TfrmMain.GetCurrentData;这种设计模式不太好,这种习惯在大项目时容易出现隐蔽性的问题,
过程不需要提供参数,也没有设计为带返回值的函数,而且又使用了非静态变量!建议1:建立一个独立执行的类,在类中定义要静态使用的变量,又类来负责创建和释放,提供更有意义和明确的函数,
此函数带GET开头却连基本返回值都不存在!建议2:在频繁调用的方法中尽量设计少的创建和释放动作,
当多线程模式时,应考虑创建和释放时的线程安全,其次,本人最近在D7下多线程内存申请操作出现枯竭,加入同步控制后,问题得到解决(但资料显示D7本身申请内存是线程安全的),到目前还找不出原因,只能说,线程安全应该更多的把主动权把握在自己手中!
频繁的申请和释放容易导致内存碎片增多,运行时间长了,这些碎片也会占据不少空间!
建议3:安全的创建和释放:
try
//资源申请代码放在这里,如果资源申请时出现异常,就不会执行不该再执行的释放动作
try
//关键代码段
//有需要时,这里放 表示执行成功的返回值赋值语句
finally
//这里释放,哪怕过程没有异常或者逻辑需求性质的离开,都能释放资源
end;
except
//这里处理异常,并且又自己控制异常时的行为
//有需要时,这里放表示执行失败的返回值复制语句
end;建议4:
SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
是把常驻内存将符合条件的转移到虚拟内存,这个操作能缓解系统需求,但降低了程序的效率!
因为当代码需要操作的内存在虚拟地址空间时,就必须先把内存转到常驻内存中!建议5:
资源的使用,最好就是谁用得最多就由谁去管理,很多时候应该根据项目的需要来规划! 建议完毕,不当之处望指正!