Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Speicherfresser CreateProcess? (https://www.delphipraxis.net/142761-speicherfresser-createprocess.html)

Angel4585 3. Nov 2009 09:17


Speicherfresser CreateProcess?
 
Guten Morgen!

Ich überarbeite gerade einen Dienst der in bestimmten Intervallen einen Prozess unter einem Benutzerkonto startet.

Nun hab ich in meiner CreateProcess Methode ein Speicherleck, hab aber keine so rechte Ahnung wie genau ich damit umgehen muss. Hier mal der Code der Methode:

Delphi-Quellcode:
procedure TMyDienst.CreateNewUserProcess(AUser, APassword, ADomain, AProgram : string);
var
  ltoken : Cardinal;
  LEnv : Pointer;
  pi : TProfileInfo;
  si : STARTUPINFO;
  pri : _PROCESS_INFORMATION;
  sil : TSecurityImpersonationLevel;
  LUser, LDomain, LPassword, LProgram : string;
  reg : TRegistry;
begin

try

  LUser:=AUser;
  LPassword:=APassword;
  LDomain:=ADomain;
  LProgram:=AProgram;
    snlogger.Log(Format('mem a: %d',[SNGetWorkingSetSize]));
  try
  FillChar(sil,SizeOf(TSecurityImpersonationLevel),#0);
    snlogger.Log(Format('mem b: %d',[SNGetWorkingSetSize]));
  sil := SecurityIdentification;
    snlogger.Log(Format('mem c: %d',[SNGetWorkingSetSize]));
  if LogonUser(PAnsiChar(LUser),PAnsiChar(LDomain),PAnsiChar(LPassword),LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,ltoken)then
    begin
    snlogger.Log(Format('mem d: %d',[SNGetWorkingSetSize]));

    if DuplicateTokenEx(ltoken,TOKEN_ALL_ACCESS,nil,sil,TokenPrimary,ltoken)then
    begin
    snlogger.Log(Format('mem e: %d',[SNGetWorkingSetSize]));
    fillchar(pi,sizeof(TProfileInfo),#0);
    pi.dwSize:=sizeof(TProfileInfo);
    pi.lpUserName:=PAnsiChar(LUser);
    if(LoadUserProfile(ltoken,pi))then
      begin
    snlogger.Log(Format('mem f: %d',[SNGetWorkingSetSize]));
      if (CreateEnvironmentBlock(
        lenv,
        ltoken,
        false
      ))then
        begin
    snlogger.Log(Format('mem g: %d',[SNGetWorkingSetSize]));
        FillChar(pri,sizeof(_PROCESS_INFORMATION),#0);
        ZeroMemory(@si,sizeof(si));
        if not(CreateProcessAsUser(
            ltoken,
            nil,
            PAnsiChar(LProgram),//PChar(SN_PATH+SN_PROG+' -0000000 -q'),
            nil,
            nil,
            false,
            CREATE_UNICODE_ENVIRONMENT or CREATE_NEW_PROCESS_GROUP or NORMAL_PRIORITY_CLASS or CREATE_NO_WINDOW,  //TODO: Priorität einstellen?
            lenv,
            nil,
            si,
            pri
            ))then
          SNLogger.Log('Prozess konnte nicht gestartet werden. '+SysErrorMessage(GetLastError),ltBoth);
    snlogger.Log(Format('mem h: %d',[SNGetWorkingSetSize]));
        if not DestroyEnvironmentBlock(lenv)then snlogger.Log('EnvironmentBlock konnte nicht geschlossen werden');
        if not UnloadUserProfile(ltoken,pi.hProfile)then snlogger.Log('UserProfile konnte nicht geschlossen werden');
        if not CloseHandle(pri.hProcess)then snlogger.Log('hProcess konnte nicht geschlossen werden');
        if not CloseHandle(pri.hThread)then snlogger.Log('hThread konnte nicht geschlossen werden');
        if not CloseHandle(ltoken)then snlogger.Log('ltoken konnte nicht geschlossen werden');
    snlogger.Log(Format('mem i: %d',[SNGetWorkingSetSize]));

        //snlogger.log(inttostr(GetLastError));
        end else SNLogger.Log('Arbeitsumgebung konnte nicht erstellt werden. '+SysErrorMessage(GetLastError));
      end else SNLogger.Log('Benutzerprofil konnte nicht geladen werden. '+SysErrorMessage(GetLastError));
    end else SNLogger.Log('Duplicate nicht möglich. '+SysErrorMessage(GetLastError));
  end else SNLogger.Log('Login nicht möglich. '+SysErrorMessage(GetLastError),ltBoth);
except
  on e : exception do
    SNLogger.Log('Fehler beim Starten eines Prozesses:'+e.Message+slinebreak+SysErrorMessage(GetLastError),ltBoth);
  end;
finally
snlogger.log(syserrormessage(getlasterror));
    snlogger.Log(Format('mem j: %d',[SNGetWorkingSetSize]));
end;
end;
SNGetWorkingSetSize ist diese Methode: http://www.delphipraxis.net/internal...=218154#218154

Diese snlogger.log Methode schreibt mir den angegebenen String in ne Datei, da hab ich unter anderem folgendes:

Zitat:

03.11.2009 09:59:42: 3200 mem a: 7800
03.11.2009 09:59:42: 3200 mem b: 7800
03.11.2009 09:59:42: 3200 mem c: 7800
03.11.2009 09:59:42: 3200 mem d: 7812
03.11.2009 09:59:42: 3200 mem e: 7812
03.11.2009 09:59:42: 3200 mem f: 7856
03.11.2009 09:59:42: 3200 mem g: 7984
03.11.2009 09:59:42: 3200 mem h: 8128
03.11.2009 09:59:42: 3200 mem i: 8128
03.11.2009 09:59:42: 3200 Der Vorgang wurde erfolgreich beendet
03.11.2009 09:59:42: 3200 mem j: 8132


Das Problem eben ist, dass der Speicher nicht freigegeben wird und der Dienst irgendwann abstürzt.
Das CreateEnvironmentBlock scheint hierbei am meisten Speicher zu fressen.

Wenn ich das recht sehe, hab ich hier tokens und records, wie gebe ich die denn frei?
Oder übersehe ich ein Objekt das ich nicht freigebe?

Diese Suche anch Speicherlecks ist echt zermürbend :wall:

Assertor 3. Nov 2009 09:35

Re: Speicherfresser CreateProcess?
 
Hi,

ich frage mich, warum immer das Working Set als Maßstab verwendet wird: Das Working Set ist abhängig von anderen Anwendungen auf dem System und laufenden Anwendungen im Vorder- und Hintergrund. (hier egal) Auch das Minimieren von Fenstern verändert das Working Set.

So würde ich auf jeden Fall nicht nach Speicherlecks suchen.

Spricht etwas dagegen mit FastMM4 im FullDebugMode anzufangen, und die enthaltenen Log-Funktion zu nutzen?

Wenn das nicht hilft, kannst Du vor und nach kritischen Geschichten ein "ScanMemoryPoolForCorruptions" (so oder ähnlich, gerade kein Delphi an) von FastMM aufrufen.

Nächster Schritt wäre für mich dann eine Kontrolle der Handles, z.B. mit Tools von SysInternals oder AQtime. Auch manche Exception Tracker sind hilfreich (madExcept, EurekaLog etc).

Aber das Working Set bestimmt nicht...

Gruß Assertor

Angel4585 3. Nov 2009 09:48

Re: Speicherfresser CreateProcess?
 
Danke für die Anwort.

FastMM4 hab ich bereits im FullDebugMode aktiv, liefert mir aber - seit ich einige Löcher gestopft hab - beim Beenden vom Dienst kein Logfile(mehr).
Im Taskmanager sehe ich aber, dass der Speicherverbrauch immernoch steigt und steigt.

Dieses ScanMemoryPoolForCorruptions werd ich mal testen, danke.

Wenn ich damit auch nix finde schau ich mir noch die anderen Sachen an.

Edit: Woah innerhalb von 5 Sekunden hab ich ne 11 mb große Datei durch das ScanMemoryPoolForCorruptions bekommen :shock:

Luckie 3. Nov 2009 10:00

Re: Speicherfresser CreateProcess?
 
Zitat:

Zitat von Angel4585
Im Taskmanager sehe ich aber, dass der Speicherverbrauch immernoch steigt und steigt.

Es gibt nicht den einen Speicherverbrauch. Welchen meinst du also?

Angel4585 3. Nov 2009 10:17

Re: Speicherfresser CreateProcess?
 
Also unter Vista hat die Spalte die Beschriftung "Arbeitsspeicher (privater Arbeitssatz)".
Unter XP schau ich bei "Speicherauslastung".

Oder schau ich ander falschen Stelle?

Edit: Ich werd mir das mal mit dem ProcessExplorer von sysinternals anschauen, da sieht man das etwas detaillierter

Angel4585 3. Nov 2009 12:14

Re: Speicherfresser CreateProcess?
 
Sorry für Doppelpost..

Also im ProcessExplorer seh ich beim Physical Memory, dass das Working Set Private immer weiter ansteigt.
Das Working Set Shareable bleibt konstant.

Beim Virtual Memory steigen die Private Bytes auch immer mehr. Hier hab ich auch Page Faults, die aber soweit ich weis nicht direkt was mit dem freigeben von Speicher zu tun haben.

Edit: Kann ich denn irgendwie von den Speicherzahlen rausfinden um was genau es sich handelt, nicht freigegebene Objekte oder was anderes?

Edit2: Laut Process Explorer steigt die Anzahl der Handles auch an, anfangs bei 180, sind es jetzt schon 220.

hoika 3. Nov 2009 14:08

Re: Speicherfresser CreateProcess?
 
Hallo,

hast du die Methode mal separat (neues, leeres Projekt)
mit FastMM4 oder memcheck geprüft ?


Heiko

hoika 3. Nov 2009 14:12

Re: Speicherfresser CreateProcess?
 
Hallo,

Delphi-Quellcode:
if DuplicateTokenEx(ltoken,TOKEN_ALL_ACCESS,nil,sil,TokenPrimary,ltoken)then
Wird hier nicht das Original-Token ltoken überschrieben ?

Mach doch mal sowas.

Delphi-Quellcode:
if DuplicateTokenEx(ltoken,TOKEN_ALL_ACCESS,nil,sil,TokenPrimary,ltoken2)then

Heiko

Angel4585 4. Nov 2009 13:33

Re: Speicherfresser CreateProcess?
 
hoika du bist ein Speichergott :firejump:

Das scheints gewesen zu sein :thumb:

Jetz hab ich nur das Problem, dass ich ab und zu folgende Meldung bekomm: "Diese Sicherheitskennung kann nicht als Besitzer des Objekts zugeordnet werden"

Das seltsame daran, er sagt er kann das CreateProcessAsUser ausführen, also das liefert ein true zurück, gestartet wurde allerdings nix, das GetLastError bringt dann die Meldung...

Soll ich dafür en eigenen Thread aufmachen?


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:59 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz