這樣寫會一直吃掉記憶體嗎? |
答題得分者是:nod32
|
corey
一般會員 發表:34 回覆:44 積分:14 註冊:2003-04-19 發送簡訊給我 |
我固定每3分鐘執行一次下面這一段程式,我有觀察了它每3分鐘就會吃掉2千多k的memory
我要如何 將memory給釋放出來,有那位大大可以幫小弟解惑一下,謝謝 procedure TranSfer(OpenFileName: String); var InputData: TStringList; ReadRecord: TDataRecord; -->自定的record i: Integer; begin InputData := TStringList.Create; InputData.LoadFromFile(OpenFileName); for i := 0 to (InputData.Count - 1) do begin if InputData.Strings[i] <> '' then begin StrLCopy(ReadRecord.DataBuf,PChar(InputData.Strings[i]),SizeOf(ReadRecord.DataBuf)-1); --> 這一行好像會一直吃掉memory 並不會release出來 SaveToDataBase(ReadRecord); end; end; InputData.Free; end; 編輯記錄
taishyang 重新編輯於 2007-05-22 15:02:39, 註解 將文章分類成[問題]‧
|
zxjrainbow@21cn.com
一般會員 發表:0 回覆:3 積分:5 註冊:2002-08-11 發送簡訊給我 |
|
Coffee
版主 發表:31 回覆:878 積分:561 註冊:2006-11-15 發送簡訊給我 |
|
rotoyang
一般會員 發表:0 回覆:1 積分:0 註冊:2005-04-11 發送簡訊給我 |
|
corey
一般會員 發表:34 回覆:44 積分:14 註冊:2003-04-19 發送簡訊給我 |
===================引 用 rotoyang 文 章=================== InputData.Free; --> FreeAndNil(InputData); 這樣改, 看看記憶體的變化量. P.S. 記憶體是每次都會長嗎? 沒有下來過?? 大大你好 原按你方法去釋放記憶體 有看到變化 會增加後會遞減 經過幾天測試 又回復原狀 記憶體不會釋放一直增加,我合理懷疑 我文章所說的那一行延伸出來的記憶體 未被釋放出 還有InputData.Free; --> FreeAndNil(InputData); 這有什麼差異嗎? |
corey
一般會員 發表:34 回覆:44 積分:14 註冊:2003-04-19 發送簡訊給我 |
|
nod32
初階會員 發表:3 回覆:29 積分:31 註冊:2007-05-21 發送簡訊給我 |
建议: 为TDataRecord做一个指针类型。PDataRecord
procedure TranSfer(OpenFileName: String); var InputData: TStringList; // ReadRecord: TDataRecord; -->自定的record ReadRecord:PDataRecord; i: Integer; datalen:Integer; begin InputData := TStringList.Create; InputData.LoadFromFile(OpenFileName); New(ReadRecord); Datalen: =sizeof(ReadRecord^.DataBuf)-1; for i := 0 to (InputData.Count - 1) do begin if InputData.Strings [i] <>'' then begin //StrLCopy(ReadRecord.DataBuf,PChar(InputData.Strings [i]),SizeOf(ReadRecord.DataBuf)-1); --> 這一行好像會一直吃掉memory 並不會release出來 ZeroMemory(ReadRecord.DataBuf,datalen); move(InputData.Strings[i][1],ReadRecord.DataBuf,datalen); SaveToDataBase(ReadRecord); end; end; freemem(readrecord); InputData.Free; end; 由于不知道你Databuf的类型,可能上面的程序不一定能正确运行,但做简单修改应当可以满足。 |
corey
一般會員 發表:34 回覆:44 積分:14 註冊:2003-04-19 發送簡訊給我 |
謝謝大大
可是記憶體還是一直增加中 下為程式碼 請大大幫我看一下會是那一部份有問題 實在是找不出問題點(我個人在猜想是否在寫入資料庫那一段) type PDatarecord=^TDataRecord; TDataRecord=record case integer of 0: ( tTrande_Kind: Char; tBrokerID: array[0..3] of Char; tTraderName: array[0..9] of Char; tOrderNumber0:Char; tOrderNumber1:array[0..3] of Char; tOrderKind: Char; tInvestorID: array[0..6] of Char; tTradeDate: array[0..6] of Char; tTradeTime: array[0..7] of Char; tStockID: array[0..5] of Char; tBuySell: Char; tPirce: array[0..6] of Char; tQty: array[0..7] of Char; tSType: Char; tPBrokerID: array[0..3] of Char; tOrderSeq: array[0..6] of Char; tTradeSeq: array[0..6] of Char; tRecEof: array[0..1] of Char; ); 1: ( DataBuf: array[0..84] of Char; ); end; procedure TranSfer(OpenFileName: String); var InputData: TStringList; // ReadRecord: TDataRecord; ReadRecord:PDatarecord; i, DataLen: Integer; begin InputData := TStringList.Create; InputData.LoadFromFile(OpenFileName); New(ReadRecord); Datalen := SizeOf(ReadRecord^.DataBuf)-1; for i := 0 to (InputData.Count - 1) do begin if InputData.Strings[i] <> '' then begin // StrLCopy(ReadRecord.DataBuf,PChar(InputData.Strings[i]),SizeOf(ReadRecord.DataBuf)-1); ZeroMemory(ReadRecord,Datalen); Move(InputData.Strings[i][1],ReadRecord^.DataBuf,Datalen); SaveToDataBase(ReadRecord); // Dispose(pbyte); // ZeroMemory(@ReadRecord,SizeOf(ReadRecord.DataBuf)); end; end; FreeMemory(ReadRecord); FreeAndNil(InputData); // InputData.Free; end; procedure SaveToDataBase(SaveData: PDataRecord); var SaveSQL, ChkSQL, UpdateSQL: String; Qry: TADOQuery; tmp: Integer; const ChkPrice: array[0..6] of Char = '0000.00'; ChkQty:array[0..7] of Char = '00000000'; begin Qry := TADOQuery.Create(DataCon); Qry.Connection := DataCon; SaveSQL := 'Insert Into DailyTrade Values('; SaveSQL := SaveSQL '''' MyIpm.Ipm_Today ''''; // with SaveData do // begin if (SaveData.tTrande_Kind = '2') and (StrToInt(SaveData.tTradeSeq) > 0) then begin //成交申報成交序號加6000號 tmp := StrToInt(String(SaveData.tTradeSeq)) 6000; StrPCopy(SaveData.tTradeSeq, DupeString('0',7-Length(Trim(IntToStr(tmp)))) Trim(IntToStr(tmp))); end; if (SaveData.tTraderName = 'xxxxxxx') and (SaveData.tPBrokerID = 'xxxx') then begin Qry.SQL.Clear; UpdateSQL := 'Update DailyTrade Set Dt_PInvestorID = ' SaveData.tInvestorID ' '; UpdateSQL := UpdateSQL 'Where Dt_Tday = ''' MyIpm.Ipm_Today ''' '; UpdateSQL := UpdateSQL 'and Dt_TradeSeq = ' SaveData.tTradeSeq; Qry.SQL.Text := UpdateSQL; Qry.ExecSQL; end; if (SaveData.tBrokerID <> 'xxxx') or (SaveData.tPirce = ChkPrice) or (SaveData.tQty = ChkQty) then Exit; case SaveData.tBuySell of '1': SaveData.tBuySell := 'B'; '2': SaveData.tBuySell := 'S'; else SaveData.tBuySell := ' '; end; Qry.Close; Qry.SQL.Clear; ChkSQL := 'Select * From DailyTrade Where Dt_Tday = ''' MyIpm.Ipm_Today ''' '; ChkSQL := ChkSQL 'and Dt_TradeSeq = ' SaveData.tTradeSeq ' '; ChkSQL := ChkSQL 'and Dt_Broker = ''' SaveData.tBrokerID ''' '; ChkSQL := ChkSQL 'and Dt_InvestorID = ' SaveData.tInvestorID ' '; ChkSQL := ChkSQL 'and Dt_StockID = ''' SaveData.tStockID ''' '; ChkSQL := ChkSQL 'and Dt_BuySell = ''' SaveData.tBuySell ''' '; ChkSQL := ChkSQL 'and Dt_Price = ' SaveData.tPirce; Qry.SQL.Text := ChkSQL; Qry.Open; ---> 個人合理懷疑 是否這一段 會增加記憶體大小呢 if Qry.Eof then begin case SaveData.tTrande_Kind of '1': SaveSQL := SaveSQL ',''點選成交'''; '2': SaveSQL := SaveSQL ',''成交申報'''; else SaveSQL := SaveSQL ','''''; end; SaveSQL := SaveSQL ',''' SaveData.tBrokerID ''''; SaveSQL := SaveSQL ',''' SaveData.tTraderName ''''; SaveSQL := SaveSQL ',' SaveData.tInvestorID; SaveSQL := SaveSQL ',''' SaveData.tTradeTime ''''; SaveSQL := SaveSQL ',''' SaveData.tStockID ''''; SaveSQL := SaveSQL ',''' SaveData.tBuySell ''''; SaveSQL := SaveSQL ',' SaveData.tPirce; SaveSQL := SaveSQL ',' SaveData.tQty; case SaveData.tSType of '1': SaveSQL := SaveSQL ',''餘額'''; '2': SaveSQL := SaveSQL ',''逐筆'''; '3': SaveSQL := SaveSQL ',''券商自行選擇'''; else SaveSQL := SaveSQL ','''''; end; SaveSQL := SaveSQL ',''' SaveData.tPBrokerID ''''; SaveSQL := SaveSQL ',' SaveData.tOrderSeq; SaveSQL := SaveSQL ',' SaveData.tTradeSeq; SaveSQL := SaveSQL ',0,0,0,0)'; Qry.SQL.Clear; Qry.SQL.Text := SaveSQL; try Qry.ExecSQL; except Application.MessageBox(PChar(SaveSQL), '寫入資料錯誤', MB_ICONWARNING); end; end; // end; Qry.Close; Qry.Free; end; |
nod32
初階會員 發表:3 回覆:29 積分:31 註冊:2007-05-21 發送簡訊給我 |
由于没有测试用例,所以我也没办法跑你的程序,不过一般来说执行Query的时候内存是会增加的,但不会一直增加。
建议程序做以下修改: 1、SaveToDataBase过程中的查询与修改分成两个query来工作。 2、不知道你用的什么数据库,如果是MS SQL或是My SQL 的话,建议把保存数据以及计算的部分转移到存储过程里去做,你现在这个做法效率可能会比较低,而且也容易出错。 有关内存泄露问题,建议你可以先不调用SaveToDataBase过程空跑几次TranSfer试试,因为ADO这个东西虽然用起来简单,但内部细节并不是非常清楚,内存的增加也有可能是ADO在做缓存或者其它的事情,因此先把这部分抛开。 另外在使用PDataRecord组员的时候要加^符号比较好。 比如:SaveData.tBuySell 写成 SaveData^.tBuySell。 还有一点,现在既然已经申明了TDataRecord的指针变量,所以你的TDataRecord申明可以改成: TDataRecord=record tTrande_Kind: Char; tBrokerID: array[0..3] of Char; tTraderName: array[0..9] of Char; tOrderNumber0:Char; tOrderNumber1:array[0..3] of Char; tOrderKind: Char; tInvestorID: array[0..6] of Char; tTradeDate: array[0..6] of Char; tTradeTime: array[0..7] of Char; tStockID: array[0..5] of Char; tBuySell: Char; tPirce: array[0..6] of Char; tQty: array[0..7] of Char; tSType: Char; tPBrokerID: array[0..3] of Char; tOrderSeq: array[0..6] of Char; tTradeSeq: array[0..6] of Char; tRecEof: array[0..1] of Char; end; 因为我们有一个指针类型,可以直接向里面填数据了。 |
corey
一般會員 發表:34 回覆:44 積分:14 註冊:2003-04-19 發送簡訊給我 |
謝謝大大回覆
===================引 用 nod32 文 章=================== 由于没有测试用例,所以我也没办法跑你的程序,不过一般来说执行Query的时候内存是会增加的(確定了Qry.Open記憶體一直增加),但不会一直增加(因為我固定每一段時間就去讀檔是否有新資料)。 建议程序做以下修改: 1、SaveToDataBase过程中的查询与修改分成两个query来工作(拆開來還是一樣 因為是ado的問題)。 2、不知道你用的什么数据库,如果是MS SQL(yes)或是My SQL 的话,建议把保存数据以及计算的部分转移到存储过程里(Cilent/Server架構嗎)去做,你现在这个做法效率可能会比较低,而且也容易出错(是有要改但要有時間.....@@時間永遠不夠用)。 有关内存泄露问题,建议你可以先不调用SaveToDataBase过程空跑几次TranSfer试试,因为ADO这个东西虽然用起来简单,但内部细节并不是非常清楚,内存的增加也有可能是ADO在做缓存或者其它的事情,因此先把这部分抛开(目前可以確定ado每open一次就會增加記憶體,這方面不知道可參考什麼資料來修改,請指導)。 另外在使用PDataRecord组员的时候要加^符号比较好。 比如:SaveData.tBuySell 写成 SaveData^.tBuySell(了解 謝謝)。 还有一点,现在既然已经申明了TDataRecord的指针变量,所以你的TDataRecord申明可以改成: TDataRecord=record tTrande_Kind: Char; tBrokerID: array[0..3] of Char; tTraderName: array[0..9] of Char; tOrderNumber0:Char; tOrderNumber1:array[0..3] of Char; tOrderKind: Char; tInvestorID: array[0..6] of Char; tTradeDate: array[0..6] of Char; tTradeTime: array[0..7] of Char; tStockID: array[0..5] of Char; tBuySell: Char; tPirce: array[0..6] of Char; tQty: array[0..7] of Char; tSType: Char; tPBrokerID: array[0..3] of Char; tOrderSeq: array[0..6] of Char; tTradeSeq: array[0..6] of Char; tRecEof: array[0..1] of Char; end; 因为我们有一个指针类型,可以直接向里面填数据了。 這2個的數值好奇怪Datalen := SizeOf(ReadRecord^.DataBuf)-1; ----> Datalen = 84 Datalen := SizeOf(ReadRecord^)-1; -----> Datalen = 85 |
Stallion
版主 發表:52 回覆:1600 積分:1995 註冊:2004-09-15 發送簡訊給我 |
以New要來的記憶體,必須以Dispose來歸還,以GetMem要來的記憶體,要以FreeMem來歸還記憶體。
<textarea cols="60" rows="10" class="delphi" name="code"> procedure TranSfer(OpenFileName: String); var InputData: TStringList; // ReadRecord: TDataRecord; ReadRecord:PDatarecord; i, DataLen: Integer; begin InputData := TStringList.Create; InputData.LoadFromFile(OpenFileName); New(ReadRecord); //配置一個指向DataRecord指標的記憶體空間,不用時應該 Dispose(ReadRecord) Datalen := SizeOf(ReadRecord^.DataBuf)-1; for i := 0 to (InputData.Count - 1) do begin if InputData.Strings[i] <> '' then begin // StrLCopy(ReadRecord.DataBuf,PChar(InputData.Strings[i]),SizeOf(ReadRecord.DataBuf)-1); ZeroMemory(ReadRecord,Datalen); Move(InputData.Strings[i][1],ReadRecord^.DataBuf,Datalen); SaveToDataBase(ReadRecord); // Dispose(pbyte); // ZeroMemory(@ReadRecord,SizeOf(ReadRecord.DataBuf)); end; end; FreeMemory(ReadRecord); //這個函數我查過不在VCL也不在WINAPI,不知道是作啥的,但看起來是要釋放之前要來的記憶體。 FreeAndNil(InputData); // InputData.Free; end; </textarea> |
corey
一般會員 發表:34 回覆:44 積分:14 註冊:2003-04-19 發送簡訊給我 |
謝謝 Stallion 大大回覆
目前如以單跑不寫入DB 在DEBUG追蹤狀態下 問題出在TADOQuery.Open 不知道為什麼ADO會一直增加Memory ===================引 用 Stallion 文 章=================== 以New要來的記憶體,必須以Dispose來歸還,以GetMem要來的記憶體,要以FreeMem來歸還記憶體。 <textarea class="delphi" rows="10" cols="60" name="code"> procedure TranSfer(OpenFileName: String); var InputData: TStringList; // ReadRecord: TDataRecord; ReadRecord:PDatarecord; i, DataLen: Integer; begin InputData := TStringList.Create; InputData.LoadFromFile(OpenFileName); New(ReadRecord); //配置一個指向DataRecord指標的記憶體空間,不用時應該 Dispose(ReadRecord) Datalen := SizeOf(ReadRecord^.DataBuf)-1; for i := 0 to (InputData.Count - 1) do begin if InputData.Strings[i] <> '' then begin // StrLCopy(ReadRecord.DataBuf,PChar(InputData.Strings[i]),SizeOf(ReadRecord.DataBuf)-1); ZeroMemory(ReadRecord,Datalen); Move(InputData.Strings[i][1],ReadRecord^.DataBuf,Datalen); SaveToDataBase(ReadRecord); // Dispose(pbyte); // ZeroMemory(@ReadRecord,SizeOf(ReadRecord.DataBuf)); end; end; FreeMemory(ReadRecord); //這個函數我查過不在VCL也不在WINAPI,不知道是作啥的,但看起來是要釋放之前要來的記憶體。 FreeAndNil(InputData); // InputData.Free; end; </textarea> |
corey
一般會員 發表:34 回覆:44 積分:14 註冊:2003-04-19 發送簡訊給我 |
目前解決方案 如下程式碼 可維持Memory 不會持續增加
個人覺的好奇怪 在SaveToDataBase 也有正常釋放 和現在寫法 有什麼不同? Qry := TADOQuery.Create(Nil); UQry := TADOQuery.Create(Nil); Qry.Connection := DataCon; UQry.Connection := DataCon; InputData := TStringList.Create; InputData.LoadFromFile(OpenFileName); New(ReadRecord); Datalen := SizeOf(ReadRecord^.DataBuf)-1; // Datalen := SizeOf(ReadRecord^)-1; for i := 0 to (InputData.Count - 1) do begin if InputData.Strings[i] <> '' then begin ZeroMemory(ReadRecord,Datalen); Move(InputData.Strings[i][1],ReadRecord^.DataBuf,Datalen); SaveToDataBase(ReadRecord,Qry,UQry); end; end; Dispose(ReadRecord); FreeAndNil(InputData); FreeAndNil(Qry); FreeAndNil(UQry); |
Mickey
版主 發表:77 回覆:1882 積分:1390 註冊:2002-12-11 發送簡訊給我 |
你好:
個人覺得沒啥錯誤會造成 Memory Leakage...就算有...也不是你造成的...哈哈 據我所知 Memory 並不是 Free 就會"吐"出來...Free只是告訴 OS...這愧記憶體...可用 要 OS...重新整理 Memory 才會"吐"出來...至於何時 OS 才會重整...這...我也不知道 但是可以用騙的..."手動"讓 OS...重整 Memory... 偷一段 ddy 的東西...嘿嘿嘿 SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF); 其細部原理請自己找找 KTop...我記得 ddy 大大說得很清楚. 另外, 個人習慣用 packed record 例如 : TSHead = packed record StreamType : Char; Name : array[0..10] of char; StreamSize : DWord; end;
編輯記錄
Mickey 重新編輯於 2007-05-24 15:51:08, 註解 無‧
|
nod32
初階會員 發表:3 回覆:29 積分:31 註冊:2007-05-21 發送簡訊給我 |
:) 不知道有什么区别,可能主要还是ADO内部的一些细节处理不同所致。另外建议每次处理完成后把ADOconnection也做一次Close试试,有可能也能把内存里的缓存清掉,但这并不一定很有效率。另外有些内存泄露检测工具可以用,不过我没用过,另外你可以反复运行100次,或1000次,再或者找台机器不停的运行看一下效果,因为有ADO的关系,那些内存虽然没有被释放,很可能是ADO的缓存,或是ADO自己处理的某些生存周期,因此短时间,很少的执行量的情况下很难测试出问题:D
不过解决问题就好,你下面的代码还要记得加上异常处理,要不一但出错,那些内存就释不出来了。 ===================引 用 corey 文 章=================== 目前解決方案 如下程式碼 可維持Memory 不會持續增加 個人覺的好奇怪 在SaveToDataBase 也有正常釋放 和現在寫法 有什麼不同? Qry := TADOQuery.Create(Nil); UQry := TADOQuery.Create(Nil); Qry.Connection := DataCon; UQry.Connection := DataCon; InputData := TStringList.Create; InputData.LoadFromFile(OpenFileName); New(ReadRecord); Datalen := SizeOf(ReadRecord^.DataBuf)-1; // Datalen := SizeOf(ReadRecord^)-1; for i := 0 to (InputData.Count - 1) do begin if InputData.Strings[i] <> '' then begin ZeroMemory(ReadRecord,Datalen); Move(InputData.Strings[i][1],ReadRecord^.DataBuf,Datalen); SaveToDataBase(ReadRecord,Qry,UQry); end; end; Dispose(ReadRecord); FreeAndNil(InputData); FreeAndNil(Qry); FreeAndNil(UQry); |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |