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

多執行緒與 CopyRect函數 出現「儲存體空間不足」問題

缺席
esp_pzj
初階會員


發表:32
回覆:70
積分:40
註冊:2007-02-09

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-08-20 12:09:26 IP:59.120.xxx.xxx 訂閱
<textarea class="delphi" rows="10" cols="60" name="code">unit Get; interface uses Classes,QForms,Graphics,Jpeg,SysUtils,Dialogs; type GetPhoto = class(TThread) private { Private declarations } procedure photo(Picture:String); protected procedure Execute; override; end; implementation uses Score, ScoreSystem, Menu; { GetPhoto } procedure GetPhoto.photo(Picture:String); var Bmp : TBitmap; Bmp1 : TBitmap; Jpg : TJpegImage; begin Bmp := TBitmap.Create(); Bmp1 := TBitmap.Create(); Jpg := TJpegImage.Create(); Jpg.LoadFromFile('C:\PHOTO1\' Picture '.jpg'); //開起jpg檔案 Bmp.Assign(Jpg); //轉為bmp檔案 Bmp1.Width:=2650; Bmp1.Height:=1700; Bmp1.Canvas.CopyRect(Rect(0,0,Bmp1.Width,Bmp1.Height),Bmp.Canvas,Rect(100,100,Bmp1.Width-100,Bmp1.Height-100));//複製Bmp圖片至Bmp1 //此行會出現問題 儲存體空間不足 無法執行 Bmp1.SaveToFile('C:\PHOTO1\' Picture '.Bmp'); //存儲bmp1檔案 bmp.Free; jpg.Free; Bmp1.Free; end; procedure GetPhoto.Execute; var i:Integer; Picture:String; begin for i:=1 to 5 do //從記錄抓取到第幾張試卷 開始抓取 begin Picture:=IntToStr(i); photo(Picture); end; end; end.</textarea><br />
呼叫 執行緒 方式如下:
Thread1:GetPhoto;//宣告

Thread1:=GetPhoto.Create(False);//建立
Thread1.Priority:=tpNormal; //設定執行權限
Thread1.FreeOnTerminate:=True; //執行緒結束時自動釋放



請教各位前輩:

我使用多執行緒,處理 CopyRect函數來處理圖案時會出現「儲存體空間不足」。
程式碼如上, 狀況如下:
1.每張圖案大小 約 30MB
2.每當處理完一次迴圈,會出現記憶體釋放不完全的問題,大約會被吃掉30MB~60MB左右的記憶。
3.200MB 記憶體 執行 五六次迴圈 後 就會出現
「儲存體空間不足」。
4.我也會試過不使用 多執行緒 來處理 就不會出現這個問題。
5.整個系統結束,記憶體 就會 全部 釋放了。
是我那一個細節沒注意到,請各位前輩給於指點。
謝謝各位前輩


PS:附上錯誤狀況畫面及記憶使用狀況畫面
------
學藝不精 謝多多指教
附加檔案:46c913f67d5d2_123456.jpg
編輯記錄
esp_pzj 重新編輯於 2007-08-20 15:47:33, 註解 補充第5點‧
esp_pzj 重新編輯於 2007-08-20 16:08:34, 註解 無‧
esp_pzj 重新編輯於 2007-08-21 17:14:08, 註解 簡化程式時沒有注意到(i)‧
esp_pzj 重新編輯於 2007-08-22 09:12:37, 註解 無‧
shunchia63
高階會員


發表:26
回覆:141
積分:198
註冊:2007-05-22

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-08-20 12:20:18 IP:61.62.xxx.xxx 訂閱
不使用多緒  一次配置一塊Memory  

使用多緒
多個 Thread , 一次配置一塊Memory ,所以Memory可能會被吃光,

是否先Cehck Memory 在作 或 例外處理


esp_pzj
初階會員


發表:32
回覆:70
積分:40
註冊:2007-02-09

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-08-20 15:46:11 IP:59.120.xxx.xxx 訂閱

每次執行時 都以確定 多緒執行完成,不過 Memory 未釋放,我可以強制釋放 Memory嗎?


===================引 用 shunchia63 文 章===================
不使用多緒? 一次配置一塊Memory??

使用多緒??
??????????????????? 多個? Thread?,???? 一次配置一塊Memory???,所以Memory可能會被吃光,

是否先Cehck? Memory 在作?或??例外處理

?????????????????
------
學藝不精 謝多多指教
wameng
版主


發表:31
回覆:1336
積分:1188
註冊:2004-09-16

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-08-20 17:38:20 IP:61.222.xxx.xxx 訂閱
為何不直接用 StretchDraw 少了一個載體(JPG->BMP)。
多出將近三分之一的記憶體。

另外控制執行緒同時執行的最大數量。
不可能有多少就開多少執行緒,再多記憶體也不行。
排隊 執行緒數量控制。
esp_pzj
初階會員


發表:32
回覆:70
積分:40
註冊:2007-02-09

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-08-21 11:42:11 IP:59.120.xxx.xxx 訂閱
謝謝wameng 前輩的回覆,請問wameng 前輩:

StretchDraw 有裁剪的功能嗎?
如原圖 0,0,800,800我要裁剪成 10,10,790,790 是裁剪不是縮小?

執行緒我一次只執行一個 沒有同一個時間執行多個?
我執行完後等了 很久 記憶體 還是沒有 釋放


===================引 用 wameng 文 章===================
為何不直接用 StretchDraw 少了一個載體(JPG->BMP)。
多出將近三分之一的記憶體。

另外控制執行緒同時執行的最大數量。
不可能有多少就開多少執行緒,再多記憶體也不行。
排隊? 執行緒數量控制。
------
學藝不精 謝多多指教
wameng
版主


發表:31
回覆:1336
積分:1188
註冊:2004-09-16

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-08-21 15:35:21 IP:61.222.xxx.xxx 訂閱
FreeOnTerminate := True
請放在 Execute 內,不然不會釋放。

StretchDraw 不能剪裁。
不然自己畫自己,也可以。

你的問題在於Thread 沒有正確釋放
anyone
中階會員


發表:1
回覆:63
積分:52
註冊:2007-02-12

發送簡訊給我
#7 引用回覆 回覆 發表時間:2007-08-21 16:26:57 IP:59.127.xxx.xxx 未訂閱
photo(Picture:String)
photo(i);
i是Integer耶!= =
我改成photo(Picture);
能執行完,並沒有你說的問題
我把i改成15也是沒問題耶!
編輯記錄
anyone 重新編輯於 2007-08-21 16:48:34, 註解 無‧
anyone 重新編輯於 2007-08-21 16:55:03, 註解 無‧
esp_pzj
初階會員


發表:32
回覆:70
積分:40
註冊:2007-02-09

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-08-22 09:37:45 IP:59.120.xxx.xxx 訂閱
wameng 前輩 :

不太懂您這句說的意思:
為何不直接用 StretchDraw 少了一個載體(JPG->BMP)。
多出將近三分之一的記憶體。
圖檔為JPG 要先轉為BMP 才有辦法做裁剪(Canvas.CopyRect)的動作。
我的疑惑是:
1.Bmp : TBitmap;可以直接開起 JPG檔嗎?
2.還是
Jpg : TJpegImage;可以做裁剪(Canvas.StretchDraw或Canvas.CopyRect)的動作。
3.要使用那一個載體(Bmp : TBitmap或Jpg : TJpegImage還是有其他的載體)來處理,才能達到您說的減少一個載體?

在下不太清楚
wameng 前輩 意思,請前輩解惑 謝謝


我把 FreeOnTerminate := True 放在 procedure GetPhoto.Execute;內 ,還是會出現「儲存體空間不足」。

===================引 用 wameng 文 章===================
FreeOnTerminate := True
請放在 Execute 內,不然不會釋放。

StretchDraw 不能剪裁。
不然自己畫自己,也可以。

你的問題在於Thread 沒有正確釋放
------
學藝不精 謝多多指教
esp_pzj
初階會員


發表:32
回覆:70
積分:40
註冊:2007-02-09

發送簡訊給我
#9 引用回覆 回覆 發表時間:2007-08-22 09:45:15 IP:59.120.xxx.xxx 訂閱
anyone 前輩

您執行完程式後,您可以觀查 Windows工作管理員→效能→實體記憶體→可用 的記憶體
確任程式執行完 ,再次執行,再次觀查記憶體,一直重覆這個動作,您會發現 可用記憶體越來越少,最後出現儲存體儲存空間不足。

謝謝您

===================引 用 anyone 文 章===================
photo(Picture:String)
photo(i);
i是Integer耶!= =
我改成photo(Picture);
能執行完,並沒有你說的問題
我把i改成15也是沒問題耶!
------
學藝不精 謝多多指教
anyone
中階會員


發表:1
回覆:63
積分:52
註冊:2007-02-12

發送簡訊給我
#10 引用回覆 回覆 發表時間:2007-08-22 13:36:23 IP:59.127.xxx.xxx 未訂閱
如下的程式碼
程式執行時記憶體使用量為8348K
第一次按Button記憶體使用量為8444K
第二次按記憶體使用量為8472K
之後按了十幾次都跟第二次一樣你試看看吧! <textarea class="delphi" rows="10" cols="60" name="code">procedure TForm1.Button1Click(Sender: TObject); var Thread1:GetPhoto;//宣告 begin Thread1:=GetPhoto.Create(False);//建立 Thread1.Priority:=tpNormal; //設定執行權限 Thread1.FreeOnTerminate:=True; //執行緒結束時自動釋放 while not Thread1.mTerminate do sleep(100); Thread1.Terminate(); end; </textarea>
===================引 用 esp_pzj 文 章===================
anyone 前輩

您執行完程式後,您可以觀查? Windows工作管理員→效能→實體記憶體→可用 的記憶體
確任程式執行完?,再次執行,再次觀查記憶體,一直重覆這個動作,您會發現 可用記憶體越來越少,最後出現儲存體儲存空間不足。

??????? ???????????????????????????????????????????????????謝謝您

===================引 用 anyone 文 章===================
photo(Picture:String)
photo(i);
i是Integer耶!= =
我改成photo(Picture);
能執行完,並沒有你說的問題
我把i改成15也是沒問題耶!
編輯記錄
anyone 重新編輯於 2007-08-22 13:38:35, 註解 無‧
anyone 重新編輯於 2007-08-22 13:39:18, 註解 無‧
esp_pzj
初階會員


發表:32
回覆:70
積分:40
註冊:2007-02-09

發送簡訊給我
#11 引用回覆 回覆 發表時間:2007-08-23 10:12:25 IP:59.120.xxx.xxx 訂閱
anyone 請問這兩行執行目的是什麼?

  • while not Thread1.mTerminate do sleep(100);
  • Thread1.Terminate();

  • not Thread1.mTerminate 的 mTerminate 是什麼意思內?因該沒有 m,我把m拿掉還是不能run。
    會出現 「 Operator not applicable to this operand type 」 錯誤訊息
    謝謝






    ===================引 用 anyone 文 章===================
    如下的程式碼
    程式執行時記憶體使用量為8348K?
    第一次按Button記憶體使用量為8444K?
    第二次按記憶體使用量為8472K?
    之後按了十幾次都跟第二次一樣你試看看吧! <textarea class="delphi" rows="10" cols="60" name="code">procedure TForm1.Button1Click(Sender: TObject); var Thread1:GetPhoto;//宣告 begin Thread1:=GetPhoto.Create(False);//建立 Thread1.Priority:=tpNormal;???????????? //設定執行權限 Thread1.FreeOnTerminate:=True; //執行緒結束時自動釋放 while not Thread1.mTerminate do sleep(100); Thread1.Terminate(); end; </textarea>
    ------
    學藝不精 謝多多指教
    anyone
    中階會員


    發表:1
    回覆:63
    積分:52
    註冊:2007-02-12

    發送簡訊給我
    #12 引用回覆 回覆 發表時間:2007-08-23 15:34:39 IP:59.127.xxx.xxx 未訂閱
    喔!抱歉,沒注意到
    以下是Get.pas的程式碼:
    <textarea class="delphi" rows="10" cols="60" name="code">unit Get; interface uses Classes,QForms,Graphics,Jpeg,SysUtils,Dialogs; type GetPhoto = class(TThread) private { Private declarations } procedure photo(Picture:String); protected procedure Execute; override; public mTerminate:Boolean; end; implementation //uses Score, ScoreSystem, Menu; { GetPhoto } procedure GetPhoto.photo(Picture:String); var Bmp : TBitmap; Bmp1 : TBitmap; Jpg : TJpegImage; begin Bmp := TBitmap.Create(); Bmp1 := TBitmap.Create(); Jpg := TJpegImage.Create(); Jpg.LoadFromFile('C:\' Picture '.jpg'); //開起jpg檔案 Bmp.Assign(Jpg); //轉為bmp檔案 Bmp1.Width:=2650; Bmp1.Height:=1700; Bmp1.Canvas.CopyRect(Rect(0,0,Bmp1.Width,Bmp1.Height),Bmp.Canvas,Rect(100,100,Bmp1.Width-100,Bmp1.Height-100));//複製Bmp圖片至Bmp1 //此行會出現問題 儲存體空間不足 無法執行 Bmp1.SaveToFile('C:\' Picture '.Bmp'); //存儲bmp1檔案 bmp.Free; jpg.Free; Bmp1.Free; end; procedure GetPhoto.Execute; var i:Integer; Picture:String; begin Picture:='Picture'; for i:=1 to 15 do //從記錄抓取到第幾張試卷 開始抓取 begin photo(Picture); end; mTerminate:=true; exit; end; end. </textarea>
    那兩行只是暫時的測試,依所需者的功能再去做變更
    意義在於等待Thread的結束,未結束則sleep(100);
    sleep多少也依照個人需求而定
    等Thread結束時,再將Thread給Terminate
    Thread就會完全的釋放掉
    ===================引 用 esp_pzj 文 章===================
    anyone 請問這兩行執行目的是什麼?

  • while?not?Thread1.mTerminate?do?sleep(100); ??
  • Thread1.Terminate(); ??
    not?Thread1.mTerminate?的 mTerminate? 是什麼意思內?因該沒有 m,我把m拿掉還是不能run。
    會出現????「? Operator not applicable to this operand type 」?錯誤訊息
    ?????????????????????????????????????????????謝謝
    ?????????






    ===================引 用 anyone 文 章===================
    如下的程式碼
    程式執行時記憶體使用量為8348K?
    第一次按Button記憶體使用量為8444K?
    第二次按記憶體使用量為8472K?
    之後按了十幾次都跟第二次一樣你試看看吧! <textarea class="delphi" rows="10" cols="60" name="code">procedure TForm1.Button1Click(Sender: TObject); var Thread1:GetPhoto;//宣告 begin Thread1:=GetPhoto.Create(False);//建立 Thread1.Priority:=tpNormal;???????????? //設定執行權限 Thread1.FreeOnTerminate:=True; //執行緒結束時自動釋放 while not Thread1.mTerminate do sleep(100); Thread1.Terminate(); end; </textarea>
  • 編輯記錄
    anyone 重新編輯於 2007-08-23 15:39:03, 註解 無‧
    esp_pzj
    初階會員


    發表:32
    回覆:70
    積分:40
    註冊:2007-02-09

    發送簡訊給我
    #13 引用回覆 回覆 發表時間:2007-08-23 16:21:32 IP:59.120.xxx.xxx 訂閱
    感謝 anyone wameng shunchia63回覆:
    anyone 您的方法 我還是試不出來,一樣問題還是存在。
    我將程式改為 當要處理圖檔 用別一支程執行,一樣可以達到我要的目的 。

    我還是保留 多執緒的方法,如各位前輩 遇到跟我一樣的問題 或 找到決解的方式 請提供我意見。

    感謝三位前輩的寶貴意見

    ------
    學藝不精 謝多多指教
    anyone
    中階會員


    發表:1
    回覆:63
    積分:52
    註冊:2007-02-12

    發送簡訊給我
    #14 引用回覆 回覆 發表時間:2007-08-23 16:33:15 IP:59.127.xxx.xxx 未訂閱
    我試可以,還是要我寄檔案給你?
    ===================引 用 esp_pzj 文 章===================
    感謝 anyone? wameng?? shunchia63回覆:
    ??? ?
    anyone? 您的方法 我還是試不出來,一樣問題還是存在。
    ???? 我將程式改為? 當要處理圖檔 用別一支程執行,一樣可以達到我要的目的?。

    我還是保留 多執緒的方法,如各位前輩 遇到跟我一樣的問題? 或 找到決解的方式 請提供我意見。

    ????????????????????????????????????? ???? 感謝三位前輩的寶貴意見

    wameng
    版主


    發表:31
    回覆:1336
    積分:1188
    註冊:2004-09-16

    發送簡訊給我
    #15 引用回覆 回覆 發表時間:2007-08-23 17:25:30 IP:61.222.xxx.xxx 訂閱
    Dear esp_pzj

    我之所以遲遲未回復,主要認為 若 FreeOnterminate 在Execute 中,絕不會造成無法釋放的問題。
    若真無法釋放,可能原因出在沒有 Try ..Finally 因意外導致不釋放資源。
    或遭遇到檔案很大,目前記憶體無法處理的情形。

    因此若改為
    procedure GetPhoto.photo(Picture:String);
    var
    Bmp1 : TBitmap;
    Jpg : TJpegImage;
    begin
    Bmp1 := TBitmap.Create();
    Try
    Jpg := TJpegImage.Create();
    Try
    Jpg.LoadFromFile('C:\PHOTO1\' Picture '.jpg'); //開起jpg檔案
    Bmp1.Width :=2650;
    Bmp1.Height :=1700;
    Bmp1.Canvas.Draw(-100,-100,JPG);
    DeleteFile('C:\PHOTO1\' Picture '.Bmp');
    Bmp1.SaveToFile('C:\PHOTO1\' Picture '.Bmp');
    Finally
    Jpg.Free;
    end;
    Finally
    Bmp1.Free;
    end;
    end;

    希望有所助益。另原CopyRect 有放大裁減不正確。
    系統時間:2024-05-08 9:48:12
    聯絡我們 | Delphi K.Top討論版
    本站聲明
    1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
    2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
    3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!