delphi - samsung - Error del sistema. Código: 8. No hay suficiente almacenamiento disponible para procesar este comando
no hay suficiente espacio de almacenamiento tarjeta sd (7)
Tenemos algunas aplicaciones Win32 (codificadas en Delphi 2006) donde a veces el usuario recibe un mensaje de error que dice "Error del sistema. Código: 8. No hay suficiente espacio de almacenamiento disponible para procesar este comando". .
Desde el stacktrace, parece que siempre está durante la llamada a 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
Nunca he podido llegar al fondo de lo que causa esto y, como sucede, casi nunca he estado preocupado, pero me gustaría descubrir qué lo causa y, con suerte, rectificarlo ...
EDITAR: Full Stacktrace
EDIT 2: Más información ... El cliente que experimentó esto hoy ha tenido mi aplicación instalada durante aproximadamente 4 meses y se ejecuta en su PC 8 horas al día. El problema solo apareció hoy y siguió reapareciendo a pesar de que mató mi aplicación y la reinició. Ninguna de las otras aplicaciones en su sistema se comportó de manera extraña. Después de un reinicio, el problema desaparece por completo. ¿Esto apunta a la escasez de montones que Steve menciona?
EDIT 3: Interesante publicación de blog msdn here y here sobre el tema del montón de escritorio. Aunque no estoy seguro de si esta es la causa del problema, parece probable.
En realidad, este es un problema con la tabla ATOM. Informé de este problema a Embarcadero, ya que me está causando muchos problemas.
Si monitoreas la tabla global de átomos, verás que las aplicaciones Delphi están filtrando átomos, dejando la identificación de tu aplicación sin que caiga de la memoria:
Verás muchos de los siguientes artículos:
**Delphi000003B4*
*Controlofs0040000000009C0**
Básicamente, dado que no puede registrar más de 0xFFFF ID de mensajes de Windows tan pronto como solicite otro, el sistema devolverá " Error del sistema. Código: 8. No hay suficiente almacenamiento disponible para procesar este comando ". Entonces no podrás iniciar ninguna aplicación que cree una ventana.
Otro problema fue reportado en Embarcadero QC Central.
Este problema se presenta en Windows 7 / Windows Server 2008. El hecho de que en Windows Server 2003 y antes solía ejecutarse es debido a una implementación incorrecta, que recicla ATOM una vez que su índice se ajusta al máximo de 16384 unidades.
Siéntase libre de usar mi Monitor Atómico Global para verificar si sus aplicaciones Delphi están filtrando o no átomos.
Para solucionarlo, necesitarás un parche de Embarcadero.
He estado buscando durante 2 años y gracias a la respuesta de Jordi Corbilla ¡finalmente lo he conseguido!
En pocas palabras: la fuente Delphi tiene errores que te están causando este problema.
Vamos a entender lo que está pasando:
Windows tiene un área de memoria llamada "Tabla Atom", que sirve para que las aplicaciones se comuniquen entre sí ( ver más ).
Además, Windows tiene otra "área de memoria", llamada "Sistema de mensajes de ventana", que sirve para el mismo propósito ( ver más ).
Ambas áreas de memoria tienen "ranuras de 16k" cada una. En el primero, es posible ELIMINAR un átomo, utilizando la siguiente API de Windows:
GlobalDeleteAtom // for removing an atom added by "GlobalAddAtom"
En la segunda "área", ¡ NO PODEMOS QUITAR nada!
La función RegisterWindowMessage se usa generalmente para registrar mensajes para comunicarse entre dos aplicaciones que cooperan. Si dos aplicaciones diferentes registran la misma cadena de mensaje, las aplicaciones devuelven el mismo valor de mensaje. El mensaje permanece registrado hasta que finaliza la sesión .
Las aplicaciones compiladas de Delphi (al menos por D7) colocarán un registro en "Área de mensajes" y algunos otros registros en "Tabla de átomos " CADA VEZ QUE SEAN INICIADOS . La aplicación intenta eliminarlos cuando se cierra la aplicación, pero he encontrado muchos (y muchos) "fugas de átomos", incluso después de que se cierra la aplicación.
En este punto, puede ver que si tiene un servidor que inicia miles de aplicaciones al día, probablemente debería alcanzar el límite de 16k pronto, ¡y el problema comienza! La solución en este punto? Nada más que un solo reinicio.
¿Entonces, qué podemos hacer? Bueno, amigo, lamento decírtelo, pero tenemos que CORREGIR el código fuente de Delphi y volver a compilar todas las aplicaciones.
Primero, abra la unidad Controls.pas y reemplace la siguiente línea:
RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString));
para:
RM_GetObjectInstance := RegisterWindowMessage(''RM_GetObjectInstance'');
y luego recompile los paquetes de Delphi y sus aplicaciones.
Como he encontrado fugas de átomos incluso después de cerrar la aplicación, creé una aplicación para que la basura recolecte cualquier átomo que quede. Simplemente ejecuta el siguiente código cada hora:
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;
(Este código anterior se basó en este código )
Después de eso, ¡nunca más tuve este error de f **!
Actualización tardía:
Además, ese es el origen de este error: Error de aplicación: dirección de error 0x00012afb
Me di cuenta de este error (Código de error del sistema: 8. No hay suficiente almacenamiento ...) Recientemente, cuando usaba algún código de Twain, estaba sucediendo en mi computadora y no en mi compañero de trabajo, y la única diferencia real entre nuestras máquinas es que utilizo el pantalla portátil como un segundo monitor, por lo que las dimensiones totales de mi escritorio son más grandes.
Encontré documentación del problema señalado anteriormente por Steve Black, pero encontré una forma (que solucionó el error en mi máquina, al menos) que no requiere editar el registro:
El código anterior estaba usando
DC := GetDC(Owner.VirtualWindow);
// ...
ReleaseDC(Owner.VirtualWindow, DC);
y encontré que al reemplazarlo con esto se deshizo de mis errores
DC := CreateCompatibleDC(Owner.VirtualWindow);
// ...
DeleteDC(DC);
No sé si esto tiene relevancia para su problema, pero puede ser útil para otros en el futuro.
Para mí, fue solo un montón de TJPEGImages que se descomprimió en una presentación de diapositivas que eventualmente se quedó sin memoria.
Puede haber errores en el compilador, es una apuesta segura que es algo en su aplicación que está causando el problema. ¿Podría ser que su aplicación tenga goteras en los tiradores de las ventanas u otro objeto de GUI como bolígrafos / pinceles? Esto podría ser una causa.
Puede usar Desktop Heap Monitor de Microsoft para ver estadísticas de almacenamiento dinámico (use% etc.) y está disponible en:
Si su programa usa muchos recursos de Windows, podría ser una escasez de Recursos.
Hay una entrada de registro que se puede aumentar para aumentar el tamaño del montón para XP. Para Vista, Microsoft ya establece el valor predeterminado más alto. Recomiendo cambiar el 3072 predeterminado a al menos 8192.
Esta información está documentada en MS Knowledge Base (o busca "Memoria agotada"). Se pueden encontrar detalles adicionales sobre los valores de los parámetros en el artículo KB184802 .
Le sugiero que lea el artículo de la base de conocimiento, pero la información básica sobre el cambio es:
Ejecute el Editor del Registro (REGEDT32.EXE).
Desde el subárbol HKEY_ LOCAL_MACHINE, vaya a la siguiente clave:
/System/CurrentControlSet/Control/Session Manager/SubSystem
En el lado derecho de la pantalla, haz doble clic en la tecla:
windows
En la ventana emergente, verá un campo muy largo seleccionado. Mueva el cursor cerca del comienzo de la cadena buscando esto (los valores pueden variar):
SharedSection=1024,3072,512
SharedSection especifica el sistema y montones de escritorio con el siguiente formato:
SharedSection=xxxx,yyyy,zzz
dondexxxx
define el tamaño máximo del montón del sistema (en kilobytes),yyyy
define el tamaño del montón de escritorio yzzz
define el tamaño del montón de escritorio para una estación de ventana "no interactiva".Cambie SOLAMENTE el valor de
yyyy
a 8192 (o más) y presione OK.Salga del Editor del registro y reinicie la PC para que el cambio surta efecto.
Buena suerte.