Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Memory-Leak WMI (https://www.delphipraxis.net/85400-memory-leak-wmi.html)

El.Blindo 30. Jan 2007 12:32


Memory-Leak WMI
 
Moin,

Ich mache grad die ersten Gehversuche mit WMI. WMI scheint recht nützlich zu sein um an verschiedene Informationen zu kommen.
In meinem Beispiel geht es um Prozesse. Ich weiss zwar das es andere Möglichkeieten gibt an diese Informationen zu kommen z.B. Toolhlp32, aber mir geht es halt darum WMI zu verstehen.

Leider sind meine bisherigen Versuche nicht von erfolg gekrönt, das Ganze funktioniert zwar, aber verursacht Memory-Leaks. Ich habe das ganze soweit verfolgen können das Die Memory-Leaks irgendwie in der WMI entstehen. Denke ich zumindestens.

Aber komme irgendwie nicht zu einer Lösung, irgendwer ne Idee ?

Hier mal der Code :

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, WbemScripting_TLB, ActiveX, StdCtrls, ExtCtrls;


Type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    function getWMIProcess : TStringList;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.getWMIProcess : TStringList;
var
   l_WMILocator: ISWbemLocator;
   l_WMIServices: ISWbemServices;
   l_WMIObjectDefinition: ISWbemObject;
   l_WMIObjectSet: SWbemObjectSet;
   l_WMIObjectInstances: IEnumVariant;
   l_WMIObject: ISWbemObject;
   l_WMIPropertySet: ISWbemPropertySet;
   l_WMIProperty: ISWbemProperty;

   l_TempObj: OleVariant;
   l_ObjValue: Cardinal;

   WMI_Name : String;
   WMI_PID  : uint64;
   WMI_Tick : uint64;
   WMI_UTime : uint64;
   WMI_KTime : uint64;
   WMI_Mem  : uint64;

begin

   result := TStringList.Create;

   l_WMILocator := CoSWbemLocator.Create;
   l_WMIServices := L_WMILocator.ConnectServer('.', 'root\CIMV2', '', '', '', '', 0, nil);
   l_WMIObjectDefinition := l_WMIServices.Get('Win32_Process', wbemFlagUseAmendedQualifiers, nil);
   l_WMIObjectSet := l_WMIObjectDefinition.Instances_(0, nil);
   l_WMIObjectInstances := (l_WMIObjectSet._NewEnum) as IEnumVariant;

   while (l_WMIObjectInstances.Next(1, l_TempObj, l_ObjValue) = S_OK) do
   begin
      WMI_Tick := GetTickCount;
      l_WMIObject:= IUnknown(l_TempObj) as SWBemObject;

      l_WMIPropertySet := l_WMIObject.Properties_;

      l_WMIProperty := l_WMIPropertySet.Item('Name', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_Name := l_WMIProperty.Get_Value else WMI_Name := 'N/A';

      l_WMIProperty := l_WMIPropertySet.Item('ProcessId', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_PID := l_WMIProperty.Get_Value else WMI_PID := 0;

      l_WMIProperty := l_WMIPropertySet.Item('WorkingSetSize', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_Mem := l_WMIProperty.Get_Value div 1024 else WMI_Mem := 0;

      l_WMIProperty := l_WMIPropertySet.Item('UserModeTime', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_UTime := l_WMIProperty.Get_Value else WMI_UTime := 0;

      l_WMIProperty := l_WMIPropertySet.Item('KernelModeTime', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_KTime := l_WMIProperty.Get_Value else WMI_KTime := 0;

      result.add(IntToStr(WMI_PID) + ' : ' + WMI_Name + ' - ' +
                 IntToStr(WMI_Mem) + ' K  ' +
                 InttoStr(WMI_UTime + WMI_KTime));
   end;
   l_WMILocator := nil;
   l_WMIServices := nil;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Memo1.Lines := getWMIProcess;
end;

end.

hsg 30. Jan 2007 13:09

Re: Memory-Leak WMI
 
Deine Funktion erzeugt eine TStringList. Aber niemand gibt diese StringList wieder frei => MemoryLeak.

El.Blindo 30. Jan 2007 20:11

Re: Memory-Leak WMI
 
Tjo, leuchtet ein, aber irgendwie brauch ich ja die TStringList als Ergebnis der Function.

Aber wie krieg ich den Speicher wieder frei ?

result.free erzeugt ein Exception, das mag er nicht.

Wenn ich mir vorher ein Stringlist erstelle :

Delphi-Quellcode:
function TForm1.WhatEver : TStringList;
var
  StList   : TStringList;

Begin
  StList := TStringList.Create; // Erstellen
  try
    blah            
    blah
    blah
    StList.add(Result of blah);
  result := StList; // Zuweisen des Ergebnisses an Result
  finally
     StList.Free;  // Speicher freigeben
  end;
end;
Dann gibts auch ne Exception!

Confused, scheint nicht so einfach zu sein ne TStringlist als Rückgabewert zu haben.

Elvis 30. Jan 2007 20:17

Re: Memory-Leak WMI
 
Übergib' einfach einen Parameter vom Typen TStrings.
Dadurch kannst du eine StringList reinwerfen oder die items einer ListBox, etc.
Vergesse aber nicht BeGinUpdate am Anfang und EndUpdate am Ende auszuführen.
Sonst wird das schnell sehr lahmarschig wenn jemand die items eines Controls übergibt. ;)

El.Blindo 30. Jan 2007 20:19

Re: Memory-Leak WMI
 
Öhhh, Bahnhof :-)

Ich doof (oder unwissend). Haste mal nen Bleistift ?

omata 30. Jan 2007 20:25

Re: Memory-Leak WMI
 
Er meint das so...

Delphi-Quellcode:
procedure TForm1.getWMIProcess(Liste:TStrings);
var
   l_WMILocator: ISWbemLocator;
   l_WMIServices: ISWbemServices;
   l_WMIObjectDefinition: ISWbemObject;
   l_WMIObjectSet: SWbemObjectSet;
   l_WMIObjectInstances: IEnumVariant;
   l_WMIObject: ISWbemObject;
   l_WMIPropertySet: ISWbemPropertySet;
   l_WMIProperty: ISWbemProperty;

   l_TempObj: OleVariant;
   l_ObjValue: Cardinal;

   WMI_Name : String;
   WMI_PID  : uint64;
   WMI_Tick : uint64;
   WMI_UTime : uint64;
   WMI_KTime : uint64;
   WMI_Mem  : uint64;
begin
   l_WMILocator := CoSWbemLocator.Create;
   l_WMIServices := L_WMILocator.ConnectServer('.', 'root\CIMV2', '', '', '', '', 0, nil);
   l_WMIObjectDefinition := l_WMIServices.Get('Win32_Process', wbemFlagUseAmendedQualifiers, nil);
   l_WMIObjectSet := l_WMIObjectDefinition.Instances_(0, nil);
   l_WMIObjectInstances := (l_WMIObjectSet._NewEnum) as IEnumVariant;

   while (l_WMIObjectInstances.Next(1, l_TempObj, l_ObjValue) = S_OK) do
   begin
      WMI_Tick := GetTickCount;
      l_WMIObject:= IUnknown(l_TempObj) as SWBemObject;

      l_WMIPropertySet := l_WMIObject.Properties_;

      l_WMIProperty := l_WMIPropertySet.Item('Name', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_Name := l_WMIProperty.Get_Value else WMI_Name := 'N/A';

      l_WMIProperty := l_WMIPropertySet.Item('ProcessId', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_PID := l_WMIProperty.Get_Value else WMI_PID := 0;

      l_WMIProperty := l_WMIPropertySet.Item('WorkingSetSize', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_Mem := l_WMIProperty.Get_Value div 1024 else WMI_Mem := 0;

      l_WMIProperty := l_WMIPropertySet.Item('UserModeTime', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_UTime := l_WMIProperty.Get_Value else WMI_UTime := 0;

      l_WMIProperty := l_WMIPropertySet.Item('KernelModeTime', 0);
      if not VarIsNull(l_WMIProperty.Get_Value) then
        WMI_KTime := l_WMIProperty.Get_Value else WMI_KTime := 0;

      Liste.Append(IntToStr(WMI_PID) + ' : ' + WMI_Name + ' - ' +
                   IntToStr(WMI_Mem) + ' K  ' +
                   InttoStr(WMI_UTime + WMI_KTime));
   end;
   l_WMILocator := nil;
   l_WMIServices := nil;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  getWMIProcess(Memo1.Lines);
end;
Gruss
Thorsten

El.Blindo 30. Jan 2007 21:23

Re: Memory-Leak WMI
 
Habs mal so gemacht, funktionieren tuts immer noch genauso wie am Anfang!
NUR leider ist das Memoryleak immer noch vorhanden.

Kann man ja Wunderbar in der Ausgabe sehen. Der Timer steht auf 250ms.

Speicher beim Start: ca 7700K
Nach 1 Min : ca. 16000K
Nach 2 Min : ca. 30000K

So nach einigen Minuten 80000K

Das sieht nich gut aus!

wtf wenn ich das mal so sagen darf :-)

Achja, aus dem Liste.Append hab ich Liste.add gemacht.

Der Aufruf erfolgt so :

Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Memo1.Clear;
  getWMIProcess(Memo1.Lines);
end;

omata 30. Jan 2007 21:27

Re: Memory-Leak WMI
 
Vielleicht hast du ja noch mehr Speicherprobleme, an anderer Stelle.
Schau dir mal MemProof an, das Programm kann dir auch die Zeile zeigen, in der das Speicherleck entsteht.

Gruss
Thorsten

El.Blindo 30. Jan 2007 21:41

Re: Memory-Leak WMI
 
Hab ich schon, der schmeisst 1000 Sachen raus und will immer die System.pas, hab ich nicht.

Zudem besteht mein Programm nur aus dieser einen Funktion, eigentlich recht übersichtlich.
Im Moment komm ich immer mehr zu dem Schluss das der Fehler im WMI liegt und nicht in meiner
Source.

Den, vielmehr als eben WMI aufrufen macht mein Code ja nicht.

Hab das Ganze mal nachvollzogen indem ich die Stringlist rausgeworfen habe und einfach den Speicherbedarf per
Label ausgebe : Label1.Caption := IntToStr(WMI_Mem);

Memory-Leak immer noch vorhanden.

omata 30. Jan 2007 22:02

Re: Memory-Leak WMI
 
Ist dann wohl so. Leider kann man deinen Code nicht testen, schade.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:14 Uhr.
Seite 1 von 2  1 2      

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