1. 程式人生 > 實用技巧 >Delphi7程式出現“EOSError code8-儲存不足”問題的分析與解決

Delphi7程式出現“EOSError code8-儲存不足”問題的分析與解決

1,故障現象

程式長期執行後,出現"System Error. Code: 8. 儲存不足,無法處理此命令"錯誤。

此時檢查磁碟空間是足夠的。但打不開工作管理員。cmd命令列視窗都打不開。

關閉出錯程式後,也無法重啟。必須重啟作業系統才能恢復正常。

2,錯誤分析

https://stackoverflow.com/questions/507853/system-error-code-8-not-enough-storage-is-available-to-process-this-command

上文顯示,“Delphi apps are leaking atoms, leaving the id of your app without dropping it off from memory”,Delphi7

使用了RWM Atom進行訊息通訊,但系統無法自動釋放,當16K的空間被分配完後,就會彈出該錯誤。

採用ATOMTableMonitor程式觀察發現,RWM ATom的消耗每天約增加2000,因此很快16K的空間將耗盡,最終將導致錯誤。

3,解決方案

http://cc.embarcadero.com/Item/28963

以上網站提供了釋放RWM Atom資源的補丁。其中修復原理為Atom重複使用,避免不斷分配新的Atom,具體說明如下:

There is a file called "RWMFixUnit.pas" that contains the hack, it replaces the call to RWM in the Controls unit and uses the GlobalAtom value (that will get cleaned up) 
instead of the leaky RWM. You HAVE to add this unit before the Controls (otherwise it will complain!) and it will only work in statically linked applications.
I have simplified the implementation, so it will just reuse the global atom for the "ControlOfs" leak, all other RWM allocation will proceed as normal.

實際操作中,發現在Dephi7中編譯"RWMFixUnit.pas" 檔案時,出現錯誤

function IntrRegisterWindowMessage(lpString: PWideChar): UINT; stdcall;

begin

     Result := 0;

     try

       if Pos('ControlOfs',lpString) = 1 then Result := GlobalFindAtom(lpString);

       //This is for defensive reasons... not really needed

       if
Result = 0 then begin //if we get here we know that the GlobalAtom has not been allocated yet //so this is ***not*** the leaky ControlOfs RWM as Atom if @OrgRWMPtr <> nil then Result := OrgRWMPtr(lpString);

原因是GlobalFindAtom不接受PWideChar型別的引數。

因此,注意要修改為以下:

function IntrRegisterWindowMessage(lpString: PChar): UINT; stdcall;

begin

     Result := 0;

     try

       if Pos('ControlOfs',lpString) = 1 then Result := GlobalFindAtom((lpString));

       //This is for defensive reasons... not really needed

       if Result = 0 then

       begin

          //if we get here we know that the GlobalAtom has not been allocated yet

          //so this is ***not*** the leaky ControlOfs RWM as Atom

          if @OrgRWMPtr <> nil then

               Result := OrgRWMPtr(PWideChar(lpString));

修改後的程式,經過多日觀察,RWM Atom的消耗一直保持穩定。問題得到解決。