全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:8623
推到 Plurk!
推到 Facebook!

如何釋放動態陣列

答題得分者是:syntax
kkeenn
一般會員


發表:10
回覆:4
積分:2
註冊:2006-07-25

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-09-16 03:16:16 IP:125.229.xxx.xxx 訂閱
var
A:array of byte;//1維動態陣列宣告
B:array of array of byte;//2維動態陣列宣告
begin
setlength(A,10);//1維動態記憶體配置
setlength(B,10,10);//2維動態記憶體配置

請問像上面這種動態陣列該怎麼釋放他的記憶體
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-09-16 08:22:22 IP:203.79.xxx.xxx 訂閱
 例一:
配置:
SetLength(A,10);

釋放:
[a] SetLength(A,0); or
[b] Finalize(A); or
[c] A := nil;

/-------------------------------------------------
例二:(setlength(B,10,10)<--無此語法)

配置:
SetLength(B,10);
for I := 0 to Length(B)-1 do SetLength(B[I],10);

釋放:
(a)
for I := 0 to Length(B)-1 do SetLength(B[I],0);
SetLength(B,0);

(b)
for I := 0 to Length(B)-1 do Finalize(B[I]);
Finalize(B);

(c)
for I := 0 to Length(B)-1 do B[I] := nil;
B := nil;
編輯記錄
jow 重新編輯於 2007-09-16 08:23:44, 註解 無‧
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-09-16 23:51:06 IP:61.64.xxx.xxx 訂閱
喔!你 Pascal 語法不熟喔!

<basefont></basefont>For dynamic arrays, SetLength may take more than one length parameter (up to the
number of array dimensions).

SetLength(B, 10, 10);

B := nil 一次釋放

===================引 用 jow 文 章===================


/-------------------------------------------------
例二:(setlength(B,10,10)<--無此語法) <------- 錯,有此語法
編輯記錄
syntax 重新編輯於 2007-09-16 23:52:14, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-09-17 10:13:01 IP:210.66.xxx.xxx 訂閱
謝謝指正!
我用的是D6,查了Help好像不行,其他版本則不清楚.

procedure SetLength(var S; NewLength: Integer);


另外借版請教:(一直想要確定的觀念問題)

(1)
動態陣列變數離開其可見範圍,是否會自動被釋放,例如:

procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
A: array of Integer;
begin
SetLength(A, 100);//配置至記憶體
try
for I := 0 to Length(A)-1 do
A[I] := Random(MaxInt);
finally
/////A := nil;
end;
end;

若不將 A 設成 nil, 那麼Button1Click()執行後,
先前配置的記憶體是否會被釋放,還是會產生Memory leak?

(2)
SetLength()也可以用於 string,

procedure TForm1.Button2Click(Sender: TObject);
var
S, S2: string;
begin
S := '1234567890';
end;

procedure TForm1.Button3Click(Sender: TObject);
var
S: string;
begin
ShowMessage(IntToStr(Length(S)));
SetLength(S, 300);
try
ShowMessage(IntToStr(Length(S)));
finally
///// S := nil;<--Error
///// SetLength(S,0);
///// Finalize(S);
end;
end;

在Button2Click()中,並不需要去釋放S 所指向的記憶體,
那麼在執行Button3Click()後,會不會有Memory leak?





Coffee
版主


發表:31
回覆:878
積分:561
註冊:2006-11-15

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-09-17 10:31:32 IP:220.130.xxx.xxx 訂閱
是可以的,但是你的對象必須是明確的二維陣列,
如var a : array of array of integer;

例1根據我知道的,是會被自動釋放。
而SetLength本身也會在配置時自動釋放原先的配置。
所以SetLength(PArray, 0)相當於配置0個資料,那麼剩下的就僅有PArray本身。
因為你是在函式內,所以該資源在仍然知道其位址的狀況下會被釋放。
不會被釋放是那些你用Create,卻沒有Free,或者是該class內有動態建立記憶體區塊卻未在Destroy之前完成釋放。
或者是用GetMem、AllocMem等卻未自行回收(Dispose)。

至於例2,你應該有點搞混了,
這兩個S你應該視為Button2Click.S跟Button3Click.S,所以是互相不干擾的
但是S的可視範圍若為Unit或Class的時候,S會互相干擾,且S不會在離開函式時被回收
但是S仍然不會有memory leak的問題,因為SetLength已經幫你完成了記憶體釋放的動作。
另外,變數是隨生命週期,應該不能夠以可視範圍來計算,雖然大多數的狀況下是相同的(?)

for i:=0 to 9 do something;
ShowMessage(i);
你可以看一下Compiler產生的Warning.

===================引 用 jow 文 章===================
謝謝指正!
我用的是D6,查了Help好像不行,其他版本則不清楚.

procedure SetLength(var S; NewLength: Integer);


另外借版請教:(一直想要確定的觀念問題)

(1)
動態陣列變數離開其可見範圍,是否會自動被釋放,例如:

procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
A: array of Integer;
begin
SetLength(A, 100);//配置至記憶體
try
for I := 0 to Length(A)-1 do
A[I] := Random(MaxInt);
finally
/////A := nil;
end;
end;

若不將 A 設成 nil, 那麼Button1Click()執行後,
先前配置的記憶體是否會被釋放,還是會產生Memory leak?

(2)
SetLength()也可以用於 string,

procedure TForm1.Button2Click(Sender: TObject);
var
S, S2: string;
begin
S := '1234567890';
end;

procedure TForm1.Button3Click(Sender: TObject);
var
S: string;
begin
ShowMessage(IntToStr(Length(S)));
SetLength(S, 300);
try
ShowMessage(IntToStr(Length(S)));
finally
///// S := nil;<--Error
///// SetLength(S,0);
///// Finalize(S);
end;
end;

在Button2Click()中,並不需要去釋放S 所指向的記憶體,
那麼在執行Button3Click()後,會不會有Memory leak?


------
不論是否我發的文,在能力範圍皆很樂意為大家回答問題。
為了補我的能力不足之處,以及讓答案可以被重複的使用,希望大家能儘量以公開的方式問問題。
在引述到我的文時自然會儘量替各位想辦法,謝謝大家!
編輯記錄
Coffee 重新編輯於 2007-09-17 10:34:22, 註解 無‧
Coffee 重新編輯於 2007-09-17 10:41:52, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-09-17 11:51:15 IP:210.66.xxx.xxx 訂閱
謝謝版主的指正,真是被Delphi的Help騙到了,
動態陣列在我個人的程式碼中使用頻率很高,
因應大量的計算,特別要考量的是記憶體的使用
與釋放,雖然程式執行正常,可是在一些觀念還沒
完全確定的狀況下,總覺得有些隱憂.

在個人分享的程式中就有使用到.(定義為 TArrayOfSingle)
http://delphi.ktop.com.tw/board.php?cid=31&fid=79&tid=89743

另外在例二中,Button2Click()的 S 與 Button3Click()的 S, 當然是
兩個截然不同的區域變數,其實我要說的是Button2Click()中的 S,
Compiler會處理記憶體釋放的問題,而Button3Click()中的S則會不會?

最後是個人的一點感觸,就是經常看到一些提問,有時候雖然是一些簡單的
問題,其實背後可以衍生很多觀念上的學習,只是現在寫程式的人有些過於
著眼於浮面上的問題,像是一些漂亮的使用者介面,多好用的元件功能. 其實
Delphi 作為 OOP的程式語言,它的許多實作觀念是很值得深入研究的,或許
改天再寫個程式與大家分享討論,順便澄清一下個人在觀念上潛藏已久的錯
誤.

最後再次謝謝Syntax與版大的回應, SetLength(B,10,10), 我真的是學到了!

Coffee
版主


發表:31
回覆:878
積分:561
註冊:2006-11-15

發送簡訊給我
#7 引用回覆 回覆 發表時間:2007-09-17 12:17:11 IP:220.130.xxx.xxx 訂閱
還是會。
除非有涉及PChar或其它非String type的操作。

[code delphi]
procedure TForm1.FormDblClick(Sender: TObject);
var i:integer;
s : string;
begin
SetLength(s, 300000);
Caption:='Start';
for i:=1 to 100000000 do
begin
Application.ProcessMessages;
SetLength(s, 300000);
end;
Caption:='End';
end;

[/code]


玩一下吧XD
經測試的結果,s若為陣列也是可以,但是這應該不是被鼓勵的作法。
------
不論是否我發的文,在能力範圍皆很樂意為大家回答問題。
為了補我的能力不足之處,以及讓答案可以被重複的使用,希望大家能儘量以公開的方式問問題。
在引述到我的文時自然會儘量替各位想辦法,謝謝大家!
編輯記錄
Coffee 重新編輯於 2007-09-17 12:23:24, 註解 無‧
Coffee 重新編輯於 2007-09-17 12:24:18, 註解 無‧
Coffee 重新編輯於 2007-09-17 12:27:45, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-09-17 14:39:34 IP:210.66.xxx.xxx 訂閱
謝謝版主的回應.在這討論區中我通常收到較少的回應,
可能是我比較喜歡討論一些程式觀念上的問題,都是一些
比較沉悶的話題,尤其現在借版提問,有點不好意思.

我想表達的是像此版的提問,其實問題不難,可是其背後是
存在很多程式觀念以及Delphi底層對於資料操作和對OOP
實作的想法與技術,是很值得學習的東西.

直言之,我想知道的是個人在某些觀念是否有錯用的地方,
像這次討論的主題,是我一直感興趣的技術,大部分的考量
點著重在記憶體的配置與釋放.

(以下問題請不要回應, 只是提供一些思考方向)

**** 如果我是主考官, 我會出下面的問題 ****
**** 請描述以下程式碼在記憶體中配置與釋放的過程? ****

(1)
var
A, B: string;
begin
A := '1234567890';
B := A;<--------------------(i)
B[1] := 'X';<----------------(ii)
end;

*** 在執行(i)後,A, B 是否指向同一個記憶體位址?
*** 在執行(ii)後,A, B 是否指向同一個記憶體位址?

(2)
var
I: Integer;
A: array of Integer;
begin
SetLength(A);
try
for I := Low(A) to High(A) do
A[I] := I;
finally
A := nil;
end;
end;
*** 如果 不執行 A := nil;, 則 SetLength(A);
*** 配置的記憶體是否會被釋放?

(3)
var
I: Integer;
A: array of TObject;
begin
SetLength(A);
try
for I := Low(A) to High(A) do
A[I] := TObject.Create;
finally
for I := Low(A) to High(A) do
A[I].Free;
A := nil;
end;
end;

*** 如果 不執行
for I := Low(A) to High(A) do
A[I].Free;
A := nil;
*** 是否會產生Memory Leak?

(4)
var
V: Variants;
I, H, L: Integer;
begin
V := VarArrayCreate([0,100], varInteger);
try
L := VarArrayLowBound(V, 1);
H := VarArrayHighBound(V, 1);
for I := L to H do
V[I] := I;
finally
V := NULL;
end;
end;

*** 如果 不執行 V := NULL, 則 V := VarArrayCreate([0,100], varInteger)
*** 配置的記憶體是否會被釋放?

(5)
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
begin
try
for I := 0 to 99 do
TComponent(Self);//Owmer: Self == instance of TForm1
finally
end;
end;

**** 假設 TForm1為程式主畫面型別, 則執行Button1Click()
**** Owner[TForm1] 會不會負責將所產生的100個 TComponent,
**** 在程式結束時釋放其所佔有的記憶體?

(6)Delphi Object Pascal 在上述的幾種資料型別的操作中,
有哪些是以類似Interface Reference Count 的方式來管理
記憶體的配置與釋放?

(以上問題請不要回應, 只是提供一些思考方向)

再次謝謝版主的回應與討論, 也為借版提問表達歉意.

NOTE: 變數(含物件變數)的生命週期取決於其可視範圍(Accessibility).




編輯記錄
jow 重新編輯於 2007-09-17 14:44:10, 註解 無‧
jow 重新編輯於 2007-09-17 14:52:31, 註解 無‧
jow 重新編輯於 2007-09-17 15:00:58, 註解 無‧
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#9 引用回覆 回覆 發表時間:2007-09-17 14:56:53 IP:61.64.xxx.xxx 訂閱
恩,沒想到你用的是 D6
D7 以上都是可以,你有 D6,那實際 Compiler 測一下就知道了
不情之請,可否測試一下,並把測試結果貼上來

所有 life-time management 的變數,都會被釋放,是 Compiler 做的好事,包含動態陣列

"S := nil;<--Error " 當然是錯誤,都已經明白宣告是字串,怎會用指標?請用 S:=''; Compiler 就會知道要釋放他了
SetLength, Finalize 是通用型的函數,服務對象包含字串

只要你不使用記憶體宣告函數,如 New/Dispose
這樣所有的記憶體,Delphi 都幫你管好了(life-time management),不會有 Memory Leak
除非你要及時釋放的效果,才做 A := nil or S := ''
不然,不用去管

如有不清楚,K 書吧,建議看 Delphi 自帶的 Pascal PDF 與 Delphi X Developer's Guide
這一份文件與書仔細看完,很多問題,你會發現:「想不起來,哪裡有問題」,就這樣不見了

以上資訊,D7 以上是用 (包含 D7)

===================引 用 jow 文 章===================
謝謝指正!
我用的是D6,查了Help好像不行,其他版本則不清楚.

procedure SetLength(var S; NewLength: Integer);


另外借版請教:(一直想要確定的觀念問題)

(1)
動態陣列變數離開其可見範圍,是否會自動被釋放,例如:

procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
A: array of Integer;
begin
SetLength(A, 100);//配置至記憶體
try
for I := 0 to Length(A)-1 do
A[I] := Random(MaxInt);
finally
/////A := nil;
end;
end;

若不將 A 設成 nil, 那麼Button1Click()執行後,
先前配置的記憶體是否會被釋放,還是會產生Memory leak?

(2)
SetLength()也可以用於 string,

procedure TForm1.Button2Click(Sender: TObject);
var
S, S2: string;
begin
S := '1234567890';
end;

procedure TForm1.Button3Click(Sender: TObject);
var
S: string;
begin
ShowMessage(IntToStr(Length(S)));
SetLength(S, 300);
try
ShowMessage(IntToStr(Length(S)));
finally
///// S := nil;<--Error
///// SetLength(S,0);
///// Finalize(S);
end;
end;

在Button2Click()中,並不需要去釋放S 所指向的記憶體,
那麼在執行Button3Click()後,會不會有Memory leak?




jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#10 引用回覆 回覆 發表時間:2007-09-17 15:11:41 IP:210.66.xxx.xxx 訂閱
跟Syntax兄報告:

說是被Delphi Help 騙了,是說其中未說明可以
如此用,甚至他的Example也像我一樣的用法.

經測試以下程式碼在D6下動作正常

procedure TForm1.Button11Click(Sender: TObject);
var
I, J: Integer;
A: array of array of Integer;
begin
SetLength(A, 10, 10);
try
for I := 0 to 9 do
for J := 0 to 9 do
A[I,J] := I*10 J;
for I := 0 to 9 do
for J := 0 to 9 do
ListBox1.Items.Add(IntToStr(A[I,J]));
finally
A := nil;
end;
end;


後記:

SetLength(B, 10, 10) 真是今天才學到的好東西.

至於K書的好提議,還真的提醒了我,D5後就沒再K了,嗯,
多半是因為工作上用不到這麼多吧! 記得最後的那本書
還花了我 NT$2000, 聽說是 Delphi 的 Bible. 不過還是
謝謝你的提議.
編輯記錄
jow 重新編輯於 2007-09-17 15:38:14, 註解 無‧
jow 重新編輯於 2007-09-17 15:41:10, 註解 無‧
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#11 引用回覆 回覆 發表時間:2007-09-19 18:02:25 IP:61.64.xxx.xxx 訂閱
是的確是好書,雖然無法盡覆 Delphi 所有知識,但也是相當豐富,要 K 完,要用去不少青春
Dlphi 還我青春來阿!
在下,中文版,看過一次後,又去買英文的來狠 K
發現中文翻的雖佳,但是原文要是能看得理解,又更勝一籌

所以覺得看英文版,可以讓你更接近 Delphi 的理念與設計思路,對看 Source 的理解,更是幫助有加
不然有時看 Source 時,還真弄不懂為何要如此做,原來是有伏筆的喔!

大好青春 四位小朋友,就奉獻給 Delphi X Developer's Guide 了

===================引 用 jow 文 章===================
跟Syntax兄報告:

說是被Delphi Help 騙了,是說其中未說明可以
如此用,甚至他的Example也像我一樣的用法.

經測試以下程式碼在D6下動作正常

procedure TForm1.Button11Click(Sender: TObject);
var
I, J: Integer;
A: array of array of Integer;
begin
SetLength(A, 10, 10);
try
for I := 0 to 9 do
for J := 0 to 9 do
A[I,J] := I*10 J;
for I := 0 to 9 do
for J := 0 to 9 do
ListBox1.Items.Add(IntToStr(A[I,J]));
finally
A := nil;
end;
end;


後記:

SetLength(B, 10, 10) 真是今天才學到的好東西.

至於K書的好提議,還真的提醒了我,D5後就沒再K了,嗯,
多半是因為工作上用不到這麼多吧! 記得最後的那本書
還花了我 NT$2000, 聽說是 Delphi 的 Bible. 不過還是
謝謝你的提議.
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#12 引用回覆 回覆 發表時間:2007-09-19 22:04:02 IP:211.76.xxx.xxx 訂閱
syntax兄真是好大的感慨! 聽您一席話(敬語喔),忍不住跑去用力挖書,
嗯,以前還真買了不少,這些已經不大用得著卻又不捨丟棄的書,這個時
候活像是記憶的相本,記錄那段迷惑又痛苦不堪的學習過程.

進入Delphi之起手式在D3, 苦讀三個月突然頓悟! 之後
Charlie Calvert's Delphi 4 Unleashed這本書給了我許多有趣的主題,
像Interface之類的觀念,我很認真地實作了書中的每一個範例,對於
interface的觀念以及應用的範圍有了比較完整的認識和體驗.

因為嚐過了甜頭,自然就很貪心在天x書局花了大錢買來用力Kn,
讀著 Delphi x Developer's Guide 認真地把玩D5,雖然痛苦的學習
卻也伴隨著較多的成就感,一點一滴,心裡有一份踏實感.

話說頓悟之前的日子,那是一連串很想死的轉換過程,Windows的出現
有了一道切線,解決中文相容性的問題,做中文系統的幾乎全趴了,最慘
的是Windows資源一把抓,什麼文字頁,圖形頁通通不准碰,留個DOS視
窗算是有照顧到了.

那段日子真的K了不少書,可是多半一知半解,期間還包括侯俊傑先生
的大作深入淺出MFC(第二版),雖然我不曾真正用VC開發過專案,可
是我現在還是強烈的建議去閱讀這本書.書中內容超流暢,讀起來還
蠻舒服的,有點像在看小說,是部製作嚴謹的作品.(非廣告)

如果我有侯先生的文筆,這篇不知所謂的東東或許可以感嘆得好一些.

嗯,我書K得比syntax兄更認真些喔...

認真程度 = (大好青春 四位小朋友,就奉獻給 Delphi X Developer's Guide 了) -
(大好青春 二位小朋友,就奉獻給 Delphi X Developer's Guide 了);

認真程度 = 二位小朋友.

後記:
基本上,我前述所提的借版提問和思考方向,在程式操作上沒什問題,
說穿了我只想確定Delphi Compiler有沒有真的幫我做了該做的事.
唉, Borland/Imprise 在 D6後表現得有點差強人意. 希望CodeGear
爭氣些.

編輯記錄
jow 重新編輯於 2007-09-19 22:06:38, 註解 無‧
系統時間:2017-10-21 16:37:02
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!