Системная ошибка. Код: 8. Недостаточно памяти для обработки этой команды

У нас есть несколько приложений Win32 (закодированных в Delphi 2006), где иногда пользователь получает сообщение об ошибке «System Error. Code: 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 

Я никогда не мог понять, что вызывает это, и, как это бывает довольно редко, я не был заинтересован, но я хотел бы узнать, что вызывает его, и, надеюсь, исправить его …

EDIT: Полная Stacktrace

EDIT 2: Дополнительная информация … Клиент, который испытал это сегодня, установил мое приложение около 4 месяцев, и он работает на своем ПК 8 часов в день. Проблема появилась только сегодня и продолжала появляться, даже если он убил мое приложение и перезапустил его. Ни одно из других приложений в его системе не вел себя странно. После перезагрузки проблема полностью исчезает. Это указывает на нехватку кучи, о которой говорит Стив?

EDIT 3: Интересный пост в блоге msdn здесь и здесь, на тему кучи рабочего стола. Хотя я не уверен, является ли это причиной проблемы, это, безусловно, выглядит вероятным.

Если ваша программа использует много ресурсов Windows, это может быть нехваткой ресурсов.

Существует запись в реестре, которая может быть увеличена, чтобы увеличить размер кучи для XP. Для Vista Microsoft уже устанавливает значение по умолчанию выше. Я рекомендую изменить значение по умолчанию 3072 как минимум 8192.

Эта информация задокументирована в базе знаний MS (или поиск «Out of Memory»). Дополнительные сведения о значениях параметров приведены в статье KB184802 .

Я предлагаю вам прочитать статью базы знаний, но основная информация об изменении:

  1. Запустите редактор реестра (REGEDT32.EXE).

  2. В поддереве HKEY_ LOCAL_MACHINE перейдите к следующему ключу:

     \System\CurrentControlSet\Control\Session Manager\SubSystem 
  3. В правой части экрана дважды щелкните по ключу:

     windows 
  4. Во всплывающем окне вы увидите очень длинное поле. Переместите курсор рядом с началом строки, которая ищет (значения могут различаться):

     SharedSection=1024,3072,512 
  5. SharedSection определяет кучи System и desktop в следующем формате: SharedSection=xxxx,yyyy,zzz где xxxx определяет максимальный размер общесистемной кучи (в килобайтах), yyyy определяет размер кучи рабочего стола, а zzz определяет размер рабочей области для «неинтерактивной» оконной станции.

  6. Измените ТОЛЬКО значение yyyy на 8192 (или больше) и нажмите OK.

  7. Выйдите из редактора реестра и перезагрузите компьютер, чтобы изменения вступили в силу.

Удачи.

На самом деле это проблема с таблицей ATOM. Я сообщил об этой проблеме Эмбаркадеро, поскольку это вызывает у меня много огорчений.

Если вы будете контролировать глобальную таблицу атомов, вы увидите, что приложения Delphi просачивают атомы, оставляя id вашего приложения, не отбрасывая его из памяти:

Вы увидите множество следующих предметов:

 **Delphi000003B4* *Controlofs0040000000009C0** 

В принципе, поскольку вы не можете зарегистрировать больше, чем 0xFFFF, идентификационный код Windows, как только вы попросите другого, система вернет « Системная ошибка». Код: 8. Недостаточно памяти для обработки этой команды ». Тогда вы не сможете запустить любое приложение, создающее окно.

Еще одна проблема была отмечена в Embarcadero QC Central.

Эта проблема возникает в Windows 7 / Windows Server 2008. Тот факт, что в Windows Server 2003 и до того, как он запускался, вызван неправильной реализацией, которая перерабатывает ATOM после того, как их индекс обернут максимум 16384 единиц.

Не стесняйтесь использовать мой монитор Global Atom для проверки того, что ваши приложения Delphi просачивают атомы или нет.

Чтобы исправить это, вам понадобится патч от Embarcadero.

Я искал 2 года, и благодаря ответу Джорди Корбиллы я наконец получил его!

В нескольких словах: у источника Delphi есть ошибки, которые вызывают у вас эту проблему!

Давайте поймем, что происходит:

В Windows есть область памяти, называемая «Таблица Atom», которая служит приложениям, взаимодействующим друг с другом ( см. Больше ).

Кроме того, Windows имеет еще одну «область памяти», называемую «Window Message System», которая служит для той же цели ( см. Больше ).

Обе области памяти имеют слоты «16k». В первом из них можно удалить REMOVE , используя следующий API Windows:

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

Во второй «области» мы просто НЕ МОЖЕМ УДАЛИТЬ ВСЕ !

Функция RegisterWindowMessage обычно используется для регистрации сообщений для связи между двумя взаимодействующими приложениями. Если два разных приложения регистрируют одну и ту же строку сообщений, приложения возвращают одно и то же значение сообщения. Сообщение остается зарегистрированным до окончания сеанса .

Скомпилированные приложения Delphi (по крайней мере, по D7) будут помещать запись в «область обмена сообщениями», а некоторые другие записи в «Таблице Atom» КАЖДЫЙ РАЗ ОНИ НАЧАЛСЯ . Приложение пытается удалить их, когда приложение закрывается, но я обнаружил много (и многих) «утечек атомов» даже после закрытия приложения.

На этом этапе вы можете увидеть, что если у вас есть сервер, который запускает тысячи приложений в день, вы, вероятно, должны скоро достигнуть предела 16k, и проблема начнется! Решение в этот момент? Ничего, кроме одной перезагрузки.

Так что мы можем сделать? Хорошо, мой друг, мне жаль вам говорить, но нам нужно исправить исходный код Delphi и перекомпилировать все приложения.

Сначала откройте блок 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; 

(Этот код был основан на этом коде )

После этого у меня никогда не было этой ошибки f ** снова!

Позднее обновление:

Кроме того, это источник этой ошибки: Ошибка приложения: адрес ошибки 0x00012afb

Вы можете использовать Desktop Heap Monitor от Microsoft для просмотра статистики кучи (используйте% и т. Д.) И доступны по адресу:

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

Я заметил эту ошибку (System Error. Code: 8. Недостаточно памяти …) в последнее время при использовании некоторого кода Twain, это происходило на моем компьютере, а не на моем коллеге, и единственная реальная разница между нашими машинами заключается в том, что я использую экран ноутбука в качестве второго монитора, поэтому мои общие размеры рабочего стола больше.

Я нашел документацию по проблеме, указанную выше Стивом Блэком, но я нашел способ (который исправил ошибку на моей машине, по крайней мере), которая не требует редактирования реестра:

Старый код использовался

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

и я обнаружил, что замена его на это избавилась от моих ошибок

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

Я не знаю, имеет ли это отношение к вашей проблеме, но может быть полезно для других в будущем.

В компиляторе могут быть ошибки, это справедливая ставка, что в приложении что-то вызывает проблему. Может ли быть, что ваше приложение пропускает дескрипторы окон или какой-либо другой объект графического интерфейса, например, ручки / кисти? Это может быть причиной.

Для меня это была всего лишь куча TJPEGImages, декомпрессирующаяся в стиле слайд-шоу, которая в конечном итоге закончилась нехваткой памяти.

  • Хостинг среды выполнения .NET в программе Delphi
  • Рабочий пример CreateJobObject / SetInformationJobObject pinvoke в .net?
  • Создание приложения без windows
  • malloc () против HeapAlloc ()
  • Как отправить штрихи клавиш в окно без необходимости его активации с помощью Windows API?
  • Контролировать использование сети процесса?
  • Проверьте правильность пути
  • Как определить текущее разрешение экрана?
  • Включение / выключение монитора
  • Глобальный Ключ для клавиатуры от службы Windows
  • Почему ExitProcess необходим под Win32, когда вы можете использовать RET?
  • Interesting Posts

    Linux найти команду для перемещения файлов

    Опции для встраивания Chromium вместо IE WebBrowser с WPF / C #

    Являются ли адаптеры HDMI для VGA действительно специфичными для устройства?

    форматирование строки в формате валюты в отчете jasper

    Функциональные сигнатурные выражения как аргументы шаблона C ++

    Заставить приложение без метро запускать полноэкранный режим вне рабочего стола?

    Не удалось войти в систему. Проверьте подключение к сети и повторите попытку.

    Как быстро переместить текущее окно на другой вид задачи / рабочего стола в Windows 10?

    Раздражение автоматически изменяющихся типов столбцов в Проводнике Windows в случае аудио / видео файлов

    Вызовите по имени vs call по значению в Scala, необходимо разъяснение

    Как получить каталог, в котором находится исполняемый файл jar?

    Блокировка файла хоста, доступная для всех компьютеров в локальной сети

    Недопустимые права

    Как стереть жесткий диск USB

    Как я могу сделать снимок экрана моего экрана входа в Windows 7?

    Давайте будем гением компьютера.