「要求系統釋放記憶體」的心得
原理是在程式中動態配置一個很大的記憶體,比現有可用的實體記憶體還大,這時系統為了滿足這個「正在執行中」的程式的要求,於是將一些已不太使用的記憶體區塊放到虛擬記憶體中。
在實際撰寫「要求系統釋放記憶體」的程式時發現,當程式向系統要一塊很大的 Buffer 時,如 char *pBuffer=new char[200*1024*1024]; 系統並不是將「實體記憶體」分配給它,而是將「虛擬記憶體」分配給它。
當程式對於 pBuffer[i] 作存取時,才發現「實體記憶體」的大小開始變小了,不過此程式所占用的「虛擬記憶體」並沒有變小喔。而當「實體記憶體」變得只剩不到 1MB 時,可以發現系統速度變慢了,這是因為系統開始整理記憶體了,把一些已不太使用的記憶體區塊釋放,此時,可以發現其他程式所占用實體記憶體的大小開始變小了,同樣地,其他程式所占用的「虛擬記憶體」並沒有變小或變大,也就是說,沒有所謂「將不用的實體記憶體放到虛擬記憶體」?是這樣嗎?
但是程式執行速度明顯變慢,而且可以看到(聽到)硬碟正在努力地存取中,有可能是將不用的實體記憶體內的資料「更新」回虛擬記憶體中。(這只是猜想)
為了加快此程式釋放記憶體的速度,於是筆者將存取 pBuffer[i] 由每 byte 都存取,改成每 1KB 只存取 1 byte、再改成每 2KB 只存取 1 byte、再改成每 4KB 只存取 1 byte、再改成每 8KB 只存取 1 byte...
當改成每 8KB 只存取 1 byte 在釋放記憶體時,發現此程式所占用的實體記憶體並沒有每 4KB 只存取 1 byte 時來得大,這也使得釋放記憶體功能失效!所以,最佳的狀態是每 4KB 只存取 1 byte,而這也有可能因系統而異。
【結論】
在釋放記憶體的過程中,其他程式所占用的虛擬記憶體並沒有增大!可以大膽的推論,程式所有必要的程式資料碼都已放在虛擬記憶體中,而在執行的過程,才將有用到的部分移到實體記憶體中執行。
而系統在使用實體記憶體時,是以 Page 為單位,一個程式在執行時有用到的程式或資料會放到可用的 Page 中,而程式所「認知」的記憶體位址,其實是系統「告知」的,所以有可能在程式中認為一個 Buffer 在執行時其記憶體是「連續」的,但這是經由系統適當配置後,讓這個程式認為它所用的 Buffer 記憶體是連續的,但真正所使用到的實體記憶體很有可能是四分五裂的區塊!
在筆者的系統中,一個 Page 的大小也許就是 4KB,這可以解釋當存取間隔是在 4KB 以下時,其占用實體記憶體的狀況相近,而當存取間隔大於 4KB 如 8KB 時,雖然在程式中也是「連續」地使用它,但它真正在實體記憶體中卻只有 8KB 中有存取到的那一個 byte 被放到一個 4KB 的 Page 中。
void __fastcall TFormMemFree::FreeMemory(int iFreeSize)
{ this->Caption="記憶體釋放中..."; iFreeSize=iFreeSize << 20; // 單位為 MB
// 方法1:無效
// char *pBuffer=new char[iFreeSize];
// delete [] pBuffer;
// 方法2:有效,要真的去存取資料才會真的配置?! char *pBuffer=new char[iFreeSize]; int iStep=4*1024; // 實驗結果 1K,2K,4K 可,8K 以上太大就不行 for(int i=iStep-1;i<iFreeSize;i += iStep) // 以 K 為單位,加快存取時間 { if(bAbort) break; // 如果要求中止,則不再向系統要記憶體 pBuffer[i]=0x0; iFreeingPercent=((i+1)>>10)*100/(iFreeSize>>10); this->Caption="記憶體釋放中..."+IntToStr(iFreeingPercent)+" %"; Application->ProcessMessages(); } delete [] pBuffer; this->Caption="記憶體釋完成!!";
}
以上的推論都是按實測的結果及小弟個人的推理所得,小弟必需先聲明,我沒有上過、看過任何作業系統的書及課,所以,以上的推論可能有錯,請懂原理的網友多多指教,讓小弟可以更了解記憶體管理。
|