Erreur De Système. Code: 8. Pas assez de mémoire disponible pour traiter cette commande

nous avons quelques applications Win32 (codées dans Delphi 2006) où parfois l'utilisateur reçoit un message d'erreur disant " erreur système. Code: 8. Pas assez de mémoire disponible pour traiter cette commande." .

de la chaîne de stockage, il semble qu'il est toujours lors de L'appel CreateWnd

Main (edc):
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

Je n'ai jamais été en mesure d'obtenir le fond de ce qui cause ceci et comme il arrive assez rarement je n'ai pas été à préoccupé, mais Je voudrais savoir ce qu'il provoque et nous espérons y remédier...

EDIT: Full Stactrace

EDIT 2: More info... Le client qui a vécu cette expérience aujourd'hui a eu mon application installée pendant environ 4 mois et il fonctionne sur son PC 8 heures par jour. Le problème n'est apparu aujourd'hui et réapparaissaient toujours même si il a tué mon application et redémarré. Aucune des autres applications de son système ne s'est comportée bizarrement. Après un redémarrage, le problème disparaît complètement. Est-ce que cela indique la pénurie de tas mentionnée par Steve?

EDIT 3: Intéressant msdn blog ici et ici sur le thème du segment de bureau. Bien que je ne suis pas sûr que ce soit la cause du problème, il semble certainement probable.

36
demandé sur Marius 2009-02-03 19:32:43

7 réponses

si votre programme utilise beaucoup de ressources windows, il pourrait y avoir une pénurie de ressources.

il y a une entrée de Registre qui peut être augmentée pour augmenter la taille du tas pour XP. Pour Vista Microsoft définit déjà la valeur par défaut plus élevée. Je recommande de changer le 3072 par défaut à au moins 8192.

cette information est documentée dans la MS Knowledge Base (ou la recherche de"Out of Memory"). Détails supplémentaires concernant les valeurs des paramètres peuvent être trouvées dans l'article KB184802 .

je vous suggère de lire l'article de la base de connaissances mais l'information de base sur le changement est:

  1. Exécutez l'Éditeur du Registre (REGEDT32.EXE.)

  2. de la sous-classe HKEY_ LOCAL_MACHINE, passez à la touche suivante:

    \System\CurrentControlSet\Control\Session Manager\SubSystem
    
  3. Sur le côté droit de l'écran double-cliquez sur la touche:

    windows 
    
  4. Sur la fenêtre pop-up, vous verrez un très long champ sélectionné. Déplacer le curseur près du début de la chaîne à la recherche de ceci (les valeurs peuvent varier):

    SharedSection=1024,3072,512
    
  5. SharedSection spécifie les tas de système et de bureau en utilisant le format suivant: SharedSection=xxxx,yyyy,zzzxxxx définit la taille maximale du tas de système (en kilooctets), yyyy définit la taille du tas par bureau, et zzz définit la taille du tas de bureau pour une station de fenêtre" non interactive".

  6. changez seulement la valeur yyyy à 8192 (ou plus) et appuyez sur OK.

  7. quitter l'Éditeur du registre et redémarrer le PC pour que le changement entre en vigueur.

bonne chance.

27
répondu Steve Black 2012-01-30 16:58:19

en fait c'est un problème avec la table D'atome. j'ai signalé ce problème à Amarcadero car il me cause beaucoup de regrets.

si vous surveillez global atom table vous verrez que les applications Delphi fuient des atomes, laissant l'id de votre application sans le laisser de mémoire:

vous verrez des charges des articles suivants:

**Delphi000003B4*

*Controlofs0040000000009C0**

en gros, puisque vous ne pouvez pas enregistrer plus de 0xFFFF windows messages différents ID dès que vous en demandez un autre, le système va retourner " erreur système. Code: 8. Pas assez de stockage est disponible pour traiter cette commande ". Alors vous ne pourrez pas démarrer une application qui crée une fenêtre.

un autre numéro a été signalé à L'Embarcadero QC Central.

ce numéro se présente sous Windows 7 / Windows Server 2008. Le fait que sur Windows Server 2003 et avant qu'il a l'habitude de courir est en raison d'une mauvaise mise en œuvre, qui recycle les atomes une fois leur indice enroulé autour du maximum de 16384 unités.

N'hésitez pas à utiliser mon Global Atom Monitor pour vérifier si vos applications Delphi fuient des atomes ou non.

pour corriger cela, vous aurez besoin d'un patch D'Amarcadero.

30
répondu Jordi Corbilla 2015-11-02 14:13:10

j'ai cherché pendant 2 ans et grâce à Jordi Corbilla réponse j'ai enfin compris!

en quelques mots: Delphi source a des bogues qui vous causent ce problème!

comprenons ce qui se passe:

Windows a une zone de mémoire appelée "table D'atome", qui sert à des applications communiquer entre eux ( voir plus ).

en outre, Windows a une autre" zone de mémoire", appelé" Système de message de fenêtre", qui sert à la même fin ( voir plus ).

ces deux zones de mémoire ont chacune des "fentes de 16k". Dans le premier, il est possible de supprimer un atome, en utilisant L'API de Windows suivante:

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

dans la deuxième "zone", nous venons ne peut pas enlever quoi que ce soit!

la fonction RegisterWindowMessage est typiquement utilisée pour enregistrer messages pour communiquer entre deux applications coopérantes. Si deux applications différentes enregistrent la même chaîne de messages, la les applications retournent la même valeur de message. le message reste enregistrés jusqu'à la fin de la session 1519100920" .

Delphi applications compilées (par D7 au moins) va mettre un disque dans "Messaging" et quelques autres enregistrements in "Atom Table " EVERY time THEY ARE STARTED . L'application essaie de les supprimer quand app se ferme, mais j'ai trouvé beaucoup (et beaucoup) de "fuites d'atomes", même après app est fermé.

à ce point vous pouvez voir que si vous avez un serveur qui démarre des milliers d'app par jour, vous devriez probablement atteindre la limite de 16k bientôt, et le problème commence! La solution à ce stade? Rien, mais un seul redémarrage.

Alors, que pouvons-nous faire? Eh bien, mon mon ami, je suis désolé de vous le dire, mais nous devons réparer le code source Delphi et recompiler toutes les applications.

d'abord, ouvrez les commandes de l'unité.pas et remplacer la ligne suivante:

RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString));

pour:

RM_GetObjectInstance := RegisterWindowMessage('RM_GetObjectInstance');

et puis recompiler les paquets Delphi et vos applications.

comme j'ai trouvé des fuites d'atomes même après que l'application est fermée, j'ai créé une application qui poubelle recueille tout atome laissé derrière. Il fonctionne juste l' code suivant toutes les heures:

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;

(ce code ci-dessus était basé sur ce code )

après ça, je n'ai plus jamais eu cette erreur de f**!

Mise À Jour Tardive:

aussi, c'est la source de cette erreur: erreur D'Application: adresse de défaut 0x00012afb

21
répondu Christian 2017-05-23 12:02:39

vous pouvez utiliser le moniteur de tas de bureau de Microsoft pour voir les statistiques de tas (utilisez % etc.) et est disponible à l'adresse suivante:

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

2
répondu HS1 2009-11-13 17:43:20

j'ai remarqué cette erreur (Erreur système. Code: 8. Pas assez de stockage... récemment, en utilisant un code Twain, cela se passait sur mon ordinateur et pas sur celui de mon collègue, et la seule vraie différence entre nos machines est que j'utilise l'écran d'ordinateur portable comme second moniteur, de sorte que mes dimensions totales de bureau sont plus grandes.

J'ai trouvé la documentation du problème pointé ci-dessus par Steve Black, mais j'ai trouvé un moyen (qui a corrigé l'erreur sur ma machine, au moins) qui ne nécessite l'édition du registre:

l'ancien code utilisait

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

et j'ai trouvé que le remplacer par ceci m'a débarrassé de mes erreurs

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



Je ne sais pas si cela a un rapport avec votre problème, mais il peut être utile pour d'autres à l'avenir.

2
répondu jasonpenny 2009-11-13 21:35:27

il pourrait y avoir des bugs dans le compilateur, il y a fort à parier que c'est quelque chose dans votre application qui cause le problème. Se pourrait-il que votre application laisse échapper des poignées de fenêtre ou un autre objet GUI comme des stylos/brosses? Ça pourrait être une cause.

0
répondu Aikislave 2014-03-13 13:33:49

pour moi, ce n'était qu'un tas de photos de TJPEGImages décompressant d'une manière de diaporama qui a fini par manquer de mémoire.

0
répondu Anton Duzenko 2018-01-25 11:50:04