看板 C_and_CPP 關於我們 聯絡資訊
各位好,小弟用Qt Creator寫了一個瀏覽照片的程式 程式中會大量的開啟指定的圖檔然後顯示到視窗中 但每次讀取到一定的量後,程式就會沒辦法再讀取圖片 嚴重甚至崩潰,檢查後才發現似乎跟程式使用的記憶體有關 每當我程式讀取的圖片佔用的記憶體到了1.2G以上, 程式很容易就無法再讀取圖片了, 我很確定我電腦的記憶體還有很多尚未使用的部分@@ 我電腦有16G的記憶體,作業系統是WIN7 64位元 我用工作管理員看效能那一欄下面的實體記憶體部分有四個內容 分別是『總共、快取的、可用、未使用』 根據我GOOGLE查到的結果,『未使用』其實只是還沒被作業系統移到『快取的』而已 電腦閒置的時間越久,未使用就會越少,快取的就會越多, 這樣電腦中的程式要用到記憶體時就可以迅速的從『快取的』取出來使用, 我打開電腦的VM ware時,『快取的』的確會大量的減少 但我發現我程式每次在讀取圖片時,『快取的』都不會減少, 反而減少的都是『未使用』 當下一張讀取的圖片檔案大小超過『未使用』時,程式就沒辦法讀取照片了@@ 而剛好我電腦的『未使用』每次都差不多是剩1.1G左右 我不知道這段敘述跟我遇到的問題有沒有相關ˇ_ˇ 我也不敢100%確定我這段敘述真的是正確的 所以想請問該怎麼樣才可以讓程式讀取更多的照片? 或者是說使用更多的記憶體 這問題我真的查了很久都查不太到解答... 本來有查到說有人講我應該要用64位元的編譯器才行, 但我在想這樣32位元的系統不就不能執行了嗎? 而且有很多32位元的程式都會超過2G以上的不是嗎@@ 不曉得有沒有高手可以指點一下的,拜託了 我寫了一個測試的讀檔程式放上來,不知道這樣有沒有違規, 有的話麻煩告知,我會速刪的。 這程式會讀取同資料夾下11.7MB的1.jpg圖檔,按一次按鈕會讀取五次 因為沒有寫執行緒,所以讀取過程會delay一段時間, 想說可以測試看看是不是真的『未使用』的部分不夠大時程式就無法讀取了。 https://mega.co.nz/#!UBsnCBSZ!hsvJ1ru5uU8KhL8zGoqsYww_3cINiUjK4Q3AAUzYQj0 不過寫了這程式反而讓我發現其他事情, 明明照片才11.7MB,可是開啟一次卻會讓程式佔用大約370M的記憶體 所以我自己的電腦只能開到三張,就沒辦法再開了 照片的大小是16744*5615,我把他相乘後再*4就是376M, 難道程式讀取照片佔用的記憶體是看這個@@? 我一直以為是看檔案大小,雖然發現這事情,不過問題還是存在ˇ_ˇ 拜託各位指點一下了,謝謝 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 49.158.60.5 ※ 文章網址: http://www.ptt.cc/bbs/C_and_CPP/M.1400609971.A.2C6.html ※ 編輯: googled (49.158.60.5), 05/21/2014 02:22:41
LPH66:看這描述似乎是 memory leak... 05/21 02:37
是說記憶體釋放問題嗎@@? 可是我的確沒有要釋放讀取到的圖片
azureblaze:11.7MB是有壓縮的的結果 要顯示一定要解壓縮 05/21 08:28
azureblaze:所以用掉376M是正確的 05/21 08:29
我了解了,謝謝解說
chchwy:32bit程式不能用超過2G的記憶體,這是 Windows 的規定 05/21 08:34
所以最高最高就只能用到2G嗎@@ 怪了...總覺得以前用XP 32位元時,玩遊戲時很容易就超過2G的說@@ 還是真的是我記錯了
azureblaze:然後"剩下800M"和 "還有一塊完整超過376M"是兩回事 05/21 08:51
所以說剩下800M都是分散的,因此沒有一塊完整376M的記憶體空間,所以才會當嗎 可是我程式讀取的圖片,每一張大約都會耗掉39M的記憶體 這樣的話只能讀取到1.2G的記憶體不是也怪怪的嗎@@ 剩下的800M感覺沒有一個區塊是完整的39M挺怪的
a27417332:然後工作管理員看到的和指標定址空間也是兩回事吧 05/21 09:08
就像上面說的,是因為沒有完整的記憶體位置,所以才沒辦法讀取嚕@@ ---------------- 謝謝各位的解說,所以真的沒有其他辦法了嗎 ※ 編輯: googled (49.158.60.5), 05/21/2014 11:20:42
Chikei:http://goo.gl/S7UyqW OS限制就在那邊,你還是把問題描述清 05/21 12:30
Chikei:楚(像是為何不釋放?)讓大家幫你想想合理的設計吧。 05/21 12:31
pcyu16:硬體跟OS 對程式來說都算先天限制吧.. 05/21 12:39
pcyu16:不管是什麼介面 應該都沒必要同時存這麼多圖片在記憶體? 05/21 12:40
pcyu16:還有就是這隻程式如果有現在以外的機器要用 怎麼辦...? 05/21 12:42
好的,其實聽你們這樣說也是,是我管理記憶體太差, 我這程式瀏覽圖片時有三種大小可以切換,分別是大張模式、中張模式、小張模式 大張模式一次顯示1張,中張是一次顯示6張,小張一次顯示36張 所以我程式一開始讀取圖片會縮放到大張模式該有的大小並丟進Vector(SourceImg)保存, 然後釋放原始圖片的記憶體 接著再看說使用者是用哪一種模式瀏覽照片,再從該SourceImg取出後縮放到符合的大小 所以這就是我會吃記憶體吃很兇的關係 本來是想說或許可以改成說需要用到哪些圖片,在臨時去開啟檔案就好, 沒有必要每張圖片都保存。 但我這程式可以提供修圖,像是R、G、B調整等等, 因此我另外又有一個Vector(ProcessImg)是儲存處理好的圖片 所以這就是我不釋放的原因,因為如果每次都把processImg跟SourceImg都釋放 要用到時才開檔並縮放,接著去處理像素,這樣會讓使用者等太久@@ 而如果我不釋放的話,假設我現在在中張模式的第五頁,要顯示第30~36張的照片 就可以直接從ProcessImg取出第30~36張的照片並顯示,不需要讓使用者等待 而如果我要把第31張的照片拿來修圖,只需要從SourceImg取出第31張照片, 處理完像素後覆蓋到ProcessImg第31張的位置就可以了 這是我程式大概的流程,不曉得是不是有不妥的地方,拜託各位指導一下了 謝謝 ※ 編輯: googled (49.158.60.5), 05/21/2014 13:27:21
blackwindy:你OS沒修好 05/21 13:11
其實真的滿後悔沒有認真修作業系統的...
donkeychen:(本人對影像處理不太熟) 不知道有沒有相關 05/21 14:34
donkeychen:http://goo.gl/loNDmg 也可能無關啦 畢竟我也不熟 05/21 14:35
donkeychen:那個轉換好像是在影像處理時用的 對於不處理儲存是否能 05/21 14:41
donkeychen:節省空間使用我不太知道 給個參考 希望有幫助 05/21 14:42
謝謝你的提供,所以是說我可以使用類似這種演算法來轉算接著再改圖 而不是像我每次使用者修圖時都是跑雙迴圈跑完所有的像素嚕@@ 我都是用 for(int i=0 ; i < img.width() ; ++i) for(int j=0 ; j < img.height() ; ++j){ //處理圖片 } 所以影像處理的速度都沒很快@@ ※ 編輯: googled (49.158.60.5), 05/21/2014 15:37:28
googled:查了一下影像處理的效率,似乎轉成char好像比較快@@ 05/21 17:44
googled:來寫個測試的程式看看 05/21 17:44
LiloHuang:處理圖片的雙重迴圈,請先跑 height 再跑 width 會較佳 05/21 18:20
想請問一下為什麼先跑height會比較佳呢? 是因為照片都是橫的(width > height)較多的關係嗎?
LiloHuang:如果要更快可以每次處理 32bit,或者用 SIMD Intrinsic 05/21 18:23
不好意思...小弟愚昧,請問什麼是每次處理32Bit跟SIMD Intrinsic是什麼意思?
LiloHuang:另外之前有貼過的連結,我再分享一次給你參考 05/21 18:25
LiloHuang:觀察記憶體用量請用 procexp.exe http://goo.gl/n7utTE 05/21 18:25
LiloHuang:搭配下 debug break point 來幫助自己釐清哪些階段增加 05/21 18:25
謝謝你,這軟體真的好用,還額外發現它可以抓出程式用了哪些DLL 不然我以前都還要把Qt的DLL一個個找出來測試
LiloHuang:真正要快就是用 OpenCL 或者 CUDA 來跑你的演算法 05/21 18:32
LiloHuang:CPU 跟 GPU 的差異 http://youtu.be/-P28LKWTzrI 05/21 18:35
平行運算完全沒有學過跟碰過@@ 不過應該是不需要到這麼快的地步,現在光是用uchar來處理像素速度就快了好多... 之前用雙迴圈跑img.pixmap(i,j)來處理3600*4500的像素要花大概1535毫秒 剛測是改成uchar後速度直接提升到94毫秒... 根本沒得比... 速度提升的的話或許就可以把一些圖片暫時釋放,讓程式不會佔用到太多記憶體 謝謝你的幫助 ※ 編輯: googled (49.158.60.5), 05/21/2014 19:16:19
LiloHuang:這就是 row major 讀取的好處,跟先跑 height 目的一樣 05/21 20:04
原來如此,謝謝你的解說
LiloHuang:假設你一個 pixel 就是 32bit 的話,每次就抓 32bit 05/21 20:06
LiloHuang:RGBA8888 轉 BGRA8888,抓 32bit 後再用 bitwise 操作 05/21 20:07
請問用bitwise是不是跟操作uchar差不多@@? 昨天在網路上查到說用uchar可以加速QImage的處理速度 但是翻到QT的文檔又說不建議大家用uchar來操作,似乎是不安全的樣子 但換成bitwise來操作不知道有沒有這問題@@ (雖然本身也沒用過bitwise來改像素,還要在查查ˇ_ˇ) QT文檔是說: Warning: If you are accessing 32-bpp image data, cast the returned pointer to QRgb* (QRgb has a 32-bit size) and use it to read/write the pixel value. You cannot use the uchar* pointer directly, because the pixel format depends on the byte order on the underlying platform. Use qRed(), qGreen(), qBlue(), and qAlpha() to access the pixels.
LiloHuang:SIMD 操作使用 MMX (64bit), SSE (128bit) 的 CPU 指令 05/21 20:10
LiloHuang:讓每次處理的資料量增加,請參考 http://goo.gl/KkIumm 05/21 20:11
LiloHuang:寫 Intrinsic 的好處是,是指 #include <xmmintrin.h> 05/21 20:11
LiloHuang:來操作那些 SIMD 的指令,而不用自己寫 inline assembly 05/21 20:12
LiloHuang:至於是不是要把資料從"空間域"轉"頻率域",要看問題類型 05/21 20:14
LiloHuang:影像處理有些細節要注意,row major 存取,記憶體對齊 05/21 20:17
LiloHuang:可以再上網多多查一些資料,大概如此。 05/21 20:18
LiloHuang:先跑 height 就是 row major 讀取,資料就是這樣擺放的 05/21 20:20
LiloHuang:這種存取方式可以有效的利用 cache,甚至做 prefetch 05/21 20:25
SIMD感覺難度好大ˇ_ˇ 果然自己不懂的地方還是好多,我今天在查說把Qt跟openCV結合 很多人都說openCV有優化過,所以速度絕對會比較快 就想把影像的部分都改成openCV來操作,但等於又要從0學習了 不過真的很謝謝你 ※ 編輯: googled (49.159.8.95), 05/22/2014 21:18:13
LiloHuang:OpenCV是個好選擇,要快可再搭配 Intel IPP,加油囉 :D 05/22 21:49
donkeychen:推LiloHuang大大 (y) 06/05 13:54