代码之家  ›  专栏  ›  技术社区  ›  AviD

系统错误。代码:8。存储空间不足,无法处理此命令

  •  36
  • AviD  · 技术社区  · 17 年前

    我们有一些Win32应用程序(在Delphi 2006中编码),用户有时会收到一条错误消息,说 “系统错误。代码:8。没有足够的存储空间来处理此命令。” .

    从stacktrace看,它似乎总是在CreateWnd调用期间

    Main ($1edc):
    004146cc +070 app.exe SysUtils               RaiseLastOSError
    00414655 +005 app.exe SysUtils               RaiseLastOSError
    004ce44c +130 app.exe Controls               TWinControl.CreateWnd
    00535a72 +022 app.exe cxControls             TcxControl.CreateWnd
    004ce82a +016 app.exe Controls               TWinControl.CreateHandle
    00553d21 +005 app.exe cxContainer            TcxContainer.CreateHandle
    00586ef1 +005 app.exe cxEdit                 TcxCustomEdit.CreateHandle
    005c331d +005 app.exe cxDropDownEdit         TcxCustomDropDownEdit.CreateHandle
    004ceaf0 +074 app.exe Controls               TWinControl.UpdateShowing
    004ceb1e +0a2 app.exe Controls               TWinControl.UpdateShowing
    004cebdc +03c app.exe Controls               TWinControl.UpdateControlState
    004d118a +026 app.exe Controls               TWinControl.CMVisibleChanged
    004cb713 +2bb app.exe Controls               TControl.WndProc
    004cf569 +499 app.exe Controls               TWinControl.WndProc
    004b727d +4c1 app.exe Forms                  TCustomForm.WndProc
    004cb3a0 +024 app.exe Controls               TControl.Perform
    004c9f6a +026 app.exe Controls               TControl.SetVisible
    004b6c46 +03a app.exe Forms                  TCustomForm.SetVisible
    004baf1b +007 app.exe Forms                  TCustomForm.Show
    004bb151 +14d app.exe Forms                  TCustomForm.ShowModal
    007869c7 +0d3 app.exe UfrmPrice      770 +19 TfrmPrice.EditPrice
    0078655d +009 app.exe UfrmPrice      628  +0 TfrmPrice.actNewBidExecute
    00431ce7 +00f app.exe Classes                TBasicAction.Execute
    004c2cb5 +031 app.exe ActnList               TContainedAction.Execute
    004c397c +050 app.exe ActnList               TCustomAction.Execute
    00431bb3 +013 app.exe Classes                TBasicActionLink.Execute
    004af384 +090 app.exe Menus                  TMenuItem.Click
    004b059f +013 app.exe Menus                  TMenu.DispatchCommand
    004b16fe +082 app.exe Menus                  TPopupList.WndProc
    004b164d +01d app.exe Menus                  TPopupList.MainWndProc
    004329a8 +014 app.exe Classes                StdWndProc
    7e4196b2 +00a USER32.dll                     DispatchMessageA
    004bea60 +0fc app.exe Forms                  TApplication.ProcessMessage
    004bea9a +00a app.exe Forms                  TApplication.HandleMessage
    004becba +096 app.exe Forms                  TApplication.Run
    008482c5 +215 app.exe AppName        129 +42 initialization
    

    我一直无法弄清是什么原因导致了这种情况,而且由于这种情况很少发生,我也没有去关注,但我想找出是什么原因导致了这种情况,并希望能够纠正它。。。

    编辑2: 更多信息。。。今天遇到这种情况的客户已经安装了我的应用程序大约4个月了,它每天在他的电脑上运行8个小时。这个问题直到今天才出现,尽管他关闭了我的应用程序并重新启动了它,但仍然不断地出现。他的系统上的其他应用程序没有一个表现异常。重新启动后,问题完全消失。这是否指向Steve提到的堆短缺?

    编辑3: here here 关于桌面堆的主题。虽然我不确定这是否是问题的原因,但看起来很有可能。

    7 回复  |  直到 17 年前
        1
  •  33
  •   Jeroen Wiert Pluimers    4 年前

    I reported this issue to Embarcadero ( saved in Wayback Machine )因为这让我很伤心。

    您将看到以下项目的负载:

    **Delphi000003B4*
    
    *Controlofs0040000000009C0**
    

    基本上,由于您在请求另一个windows消息ID时不能注册超过0xFFFF的不同windows消息ID,因此系统将返回“ 系统错误。代码:8。存储空间不足,无法处理此命令

    Another issue ( saved in Wayback Machine )在Embarcadero QC Central报告。

    此问题在Windows 7/Windows Server 2008下出现。事实上,在WindowsServer2003上以及它以前运行是因为一个错误的实现,该实现在原子的索引达到最大16384个单位时会回收原子。

    Global Atom Monitor 检查您的Delphi应用程序是否泄漏原子。

    ControlsAtomFix1.7z 从…起 www.idefixpack.de/blog/downloads .

        2
  •  29
  •   NGLN Selim Serhat Çelik    14 年前

    有一个注册表项可以增加,以提高XP的堆大小。对于Vista,Microsoft已将默认值设置得更高。我建议将默认的3072更改为至少8192。

    MS Knowledge Base (或搜索“内存不足”)。有关参数值的更多详细信息,请参阅第条 KB184802 .

    我建议您阅读knowledgebase文章,但有关更改的基本信息如下:

    1. 运行注册表编辑器(REGEDT32.EXE)。

    2. \System\CurrentControlSet\Control\Session Manager\SubSystem
      
    3. 在屏幕右侧双击键:

      windows 
      
    4. 在弹出窗口中,您将看到一个很长的选定字段。将光标移到字符串开头附近以查找(值可能不同):

      SharedSection=1024,3072,512
      
    5. SharedSection=xxxx,yyyy,zzz 哪里 xxxx yyyy 定义每个桌面堆的大小,以及 zzz 定义“非交互式”窗口站的桌面堆大小。

    6. 年份 值设置为8192(或更大),然后按OK。

    7. 退出注册表编辑器并重新启动电脑,以使更改生效。

    祝你好运

        3
  •  24
  •   Community Mohan Dere    9 年前

    我已经搜索了2年,感谢 Jordi Corbilla answer 我终于明白了!

    简言之: Delphi源代码中有导致此问题的bug!

    让我们了解发生了什么:

    see more ).

    此外,Windows还有另一个“存储区”,称为“窗口消息系统”,用于相同的目的( see more ).

    去除 atom,通过使用以下Windows API:

    GlobalDeleteAtom // for removing an atom added by "GlobalAddAtom"
    

    在第二个“区域”,我们只是 无法删除 任何东西

    RegisterWindowMessage函数通常用于注册 用于在两个协作应用程序之间通信的消息。如果 应用程序返回相同的消息值。 信息仍然存在 在会话结束前注册

    Delphi编译的应用程序(至少由D7编写)将在“消息传递区域”中放置一条记录,在“Atom表”中放置一些其他记录 每次启动时 . 应用程序试图在应用程序关闭时删除它们,但我发现很多(而且很多)“atom泄漏”,即使在应用程序关闭后也是如此。

    那么,我们能做些什么呢?我的朋友,很抱歉告诉你,我们需要修复Delphi源代码并重新编译所有应用程序。

    首先,打开unit Controls.pas并更换以下行:

    RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString));
    

    用于:

    RM_GetObjectInstance := RegisterWindowMessage('RM_GetObjectInstance');
    

    然后重新编译Delphi包和应用程序。

    由于我发现即使在应用程序关闭后原子仍会泄漏,所以我创建了一个应用程序,该应用程序可以垃圾收集任何留下的原子。它每小时只运行以下代码:

    procedure GarbageCollectAtoms;
    var i, len : integer;
        cstrAtomName: array [0 .. 1024] of char;
        AtomName, Value, procName: string;
        ProcID,lastError : cardinal;
        countDelphiProcs, countActiveProcs, countRemovedProcs, countCantRemoveProcs, countUnknownProcs : integer;
    
        // gets program's name from process' handle
        function getProcessFileName(Handle: THandle): string;
        begin
          Result := '';
          { not used anymore
          try
            SetLength(Result, MAX_PATH);
            if GetModuleFileNameEx(Handle, 0, PChar(Result), MAX_PATH) > 0 then
              SetLength(Result, StrLen(PChar(Result)))
            else
              Result := '';
            except
          end;
          }
        end;
    
        // gets the last 8 digits from the given atomname and try to convert them to and integer
        function getProcessIdFromAtomName(name:string):cardinal;
        var l : integer;
        begin
          result := 0;
          l := Length(name);
          if (l > 8) then
          begin
            try
              result := StrToInt64('$' + copy(name,l-7,8));
              except
                // Ops! That should be an integer, but it's not!
                // So this was no created by a 'delphi' application and we must return 0, indicating that we could not obtain the process id from atom name.
                result := 0;
            end;
          end;
        end;
    
        // checks if the given procID is running
        // results: -1: we could not get information about the process, so we can't determine if is active or not
        //           0: the process is not active
        //           1: the process is active
        function isProcessIdActive(id: cardinal; var processName: string):integer;
        var Handle_ID: THandle;
        begin
          result := -1;
          try
            Handle_ID := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, id);
            if (Handle_ID = 0) then
            begin
              result := 0;
            end
            else
            begin
              result := 1;
              // get program's name
              processName := getProcessFileName(Handle_ID);
              CloseHandle(Handle_ID);
            end;
            except
              result := -1;
          end;
        end;
    
        procedure Log(msg:string);
        begin
          // Memo1.Lines.Add(msg);
        end;
    
    
    begin
    
      // initialize the counters
      countDelphiProcs := 0;
      countActiveProcs := 0;
      countRemovedProcs := 0;
      countUnknownProcs := 0;
    
      // register some log
      Log('');
      Log('');
      Log('Searching Global Atom Table...');
    
      for i := $C000 to $FFFF do
      begin
        len := GlobalGetAtomName(i, cstrAtomName, 1024);
        if len > 0 then
        begin
          AtomName := StrPas(cstrAtomName);
          SetLength(AtomName, len);
          Value := AtomName;
          // if the atom was created by a 'delphi application', it should start with some of strings below
          if (pos('Delphi',Value) = 1) or
             (pos('ControlOfs',Value) = 1) or
             (pos('WndProcPtr',Value) = 1) or
             (pos('DlgInstancePtr',Value) = 1) then 
          begin
            // extract the process id that created the atom (the ProcID are the last 8 digits from atomname)
            ProcID := getProcessIdFromAtomName(value);
            if (ProcId > 0) then
            begin
              // that's a delphi process
              inc(countDelphiProcs);
              // register some log
              Log('');
              Log('AtomName: ' + value + ' - ProcID: ' + inttostr(ProcId) + ' - Atom Nº: ' + inttostr(i));
              case (isProcessIdActive(ProcID, procName)) of
                0: // process is not active
                begin
                  // remove atom from atom table
                  SetLastError(ERROR_SUCCESS);
                  GlobalDeleteAtom(i);
                  lastError := GetLastError();
                  if lastError = ERROR_SUCCESS then
                  begin
                    // ok, the atom was removed with sucess
                    inc(countRemovedProcs);
                    // register some log
                    Log('- LEAK! Atom was removed from Global Atom Table because ProcID is not active anymore!');
                  end
                  else
                  begin
                    // ops, the atom could not be removed
                    inc(countCantRemoveProcs);
                    // register some log
                    Log('- Atom was not removed from Global Atom Table because function "GlobalDeleteAtom" has failed! Reason: ' + SysErrorMessage(lastError));
                  end;
                end;
                1: // process is active
                begin
                  inc(countActiveProcs);
                  // register some log
                  Log('- Process is active! Program: ' + procName);
                end;
                -1: // could not get information about process
                begin
                  inc(countUnknownProcs);
                  // register some log
                  Log('- Could not get information about the process and the Atom will not be removed!');
                end;
              end;
            end;
          end;
        end;
      end;
      Log('');
      Log('Scan complete:');
      Log('- Delphi Processes: ' + IntTostr(countDelphiProcs) );
      Log('  - Active: ' + IntTostr(countActiveProcs) );
      Log('  - Removed: ' + IntTostr(countRemovedProcs) );
      Log('  - Not Removed: ' + IntTostr(countCantRemoveProcs) );
      Log('  - Unknown: ' + IntTostr(countUnknownProcs) );
    
      TotalAtomsRemovidos := TotalAtomsRemovidos + countRemovedProcs;
    
    end;
    

    this code )

    从那以后,我再也没有犯过这样的错误!

    最新更新:

    Application error: fault address 0x00012afb

        4
  •  2
  •   HS1    16 年前

    您可以使用Microsoft的桌面堆监视器查看堆统计信息(使用%etc),可从以下网站获得:

    http://www.microsoft.com/downloads/details.aspx?familyid=5cfc9b74-97aa-4510-b4b9-b2dc98c8ed8b&displaylang=en

        5
  •  2
  •   jasonpenny    16 年前

    我最近在使用Twain代码时注意到了这个错误(系统错误。代码:8。存储空间不足…),它发生在我的电脑上,而不是我同事的电脑上,我们机器之间唯一的真正区别是我使用笔记本电脑屏幕作为第二个显示器,因此我的桌面总尺寸更大。

    我找到了上面Steve Black指出的问题的文档,但我找到了一种不需要编辑注册表的方法(至少修复了我机器上的错误):

      DC := GetDC(Owner.VirtualWindow);
      // ...
      ReleaseDC(Owner.VirtualWindow, DC);

    我发现用这个替换它可以消除我的错误

      DC := CreateCompatibleDC(Owner.VirtualWindow);
      // ...
      DeleteDC(DC);


    我不知道这是否与你的问题有关,但它可能对将来的其他人有所帮助。

        6
  •  1
  •   bluish dmajkic    12 年前

    编译器中可能有bug,很可能是应用程序中的某些东西导致了问题。可能是你的应用程序正在泄漏窗口句柄或其他GUI对象,如笔/刷子?这可能是一个原因。

        7
  •  0
  •   Anton Duzenko    8 年前

    对我来说,这只是一堆TJPEG图像以幻灯片放映的方式解压缩,最终耗尽了内存。