![]() |
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. |
Re: Memory-Leak WMI
Deine Funktion erzeugt eine TStringList. Aber niemand gibt diese StringList wieder frei => MemoryLeak.
|
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:
Dann gibts auch ne Exception!
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; Confused, scheint nicht so einfach zu sein ne TStringlist als Rückgabewert zu haben. |
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. ;) |
Re: Memory-Leak WMI
Öhhh, Bahnhof :-)
Ich doof (oder unwissend). Haste mal nen Bleistift ? |
Re: Memory-Leak WMI
Er meint das so...
Delphi-Quellcode:
Gruss
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; Thorsten |
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; |
Re: Memory-Leak WMI
Vielleicht hast du ja noch mehr Speicherprobleme, an anderer Stelle.
Schau dir mal ![]() Gruss Thorsten |
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. |
Re: Memory-Leak WMI
Ist dann wohl so. Leider kann man deinen Code nicht testen, schade.
|
Re: Memory-Leak WMI
Wieso kann man den nicht testen ? Muss nur die WbemScripting_TLB über Import Type Library in das Project importieren, ist alles bei Delphi bei.
|
Re: Memory-Leak WMI
Ich habe leider kein WbemScripting.
|
Re: Memory-Leak WMI
Die ist zumindestens bei Delphi 7 dabei. Ausserdem hab ich gesehen das man hier irgendwo im Forum die WbemScripting.pas downloaden kann, such mal nach WMI.
Aber zurück zum Thema: Ich hab mal ein wenig geguckt und eine Componente für WMI gefunden bei Magnenta Systems. Dieser Componente liegt eine Beispiel Application bei. (Wobei, eigentlich will ich keine fertige Componente verwenden, ich will das selbst kapieren) Also gestartet das Ding, und siehe da, bei wiederholtem Abfragen einzelner Werte = MEMORY-Leak. Also entweder machen die zufällig excakt die selben Fehler wie ich, oder der fehler liegt im WMI. Scheint also tatsächlich am WMI selbst zu liegen, Schade, ist ein mächtiges Werkzeug, aber seit wann macht M$ schon mal was richtig. Kleines Edit: Hab mir mal so einige Sachen hier im Forum angeschaut, z.B. Himitsu's WMI+Demo usw., musste dabei feststellen das dieses Memory Leak wohl in jeder Application vorhanden ist. Vielleicht liegt es daran das ich SP2 nicht drauf hab, aber ehrlich gesagt hab ich kein Bock nur deswegen SP2 zu installieren, eigentlich hab ich gar keinen Bock SP2 zu installieren. Mal sehen, Morgen Abend krieg ich meinen Lappy wieder, da is Media Center SP2 drauf, schaun wie es da ist. Und weiter versucht, andere variante zum Auslesen von WMI, abgeguckt hier im Forum. Das memory Leak bleibt :-(
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; PropVal : OLEVariant; l_ObjValue: Cardinal; WMI_Name : String; WMI_PID : uint64; WMI_Tick : uint64; WMI_UTime : uint64; WMI_KTime : uint64; WMI_Mem : uint64; function GetValue(Value : String) : Variant; begin try PropVal := (l_WMIObject.Properties_.Item(Value, 0) as ISWbemProperty).Get_Value; if not (VarIsEmpty(PropVal) or VarIsNull(PropVal)) then Result := PropVal; except end; end; begin Memo1.Lines.BeginUpdate; Memo1.Clear; l_WMILocator := CoSWbemLocator.Create; try If l_WMILocator <> nil then Begin l_WMIServices := L_WMILocator.ConnectServer('.', 'root\CIMV2', '', '', '', '', 0, nil); If l_WMIServices <> nil then Begin l_WMIObjectSet := l_WMIServices.ExecQuery('SELECT * FROM Win32_Process', 'WQL', wbemFlagReturnWhenComplete, nil); If l_WMIObjectSet <> nil then with l_WMIObjectSet do Begin l_WMIObjectInstances := (l_WMIObjectSet._NewEnum) as IEnumVariant; If l_WMIObjectInstances <> nil then begin If l_WMIObjectSet.Count > 0 then Begin while (l_WMIObjectInstances.Next(1, l_TempObj, l_ObjValue) = S_OK) do begin l_WMIObject:= IUnknown(l_TempObj) as ISWBemObject; PropVal := (l_WMIObject.Properties_.Item('Name', 0) as ISWbemProperty).Get_Value; if not (VarIsEmpty(PropVal) or VarIsNull(PropVal)) then Begin WMI_Name := GetValue('Name'); WMI_PID := GetValue('ProcessId'); WMI_Mem := GetValue('WorkingSetSize') div 1024; WMI_UTime := GetValue('UserModeTime'); WMI_KTime := GetValue('KernelModeTime'); end; Liste.Add(IntToStr(WMI_PID) + ' : ' + WMI_Name + ' - ' + IntToStr(WMI_Mem) + ' K ' + InttoStr(WMI_UTime + WMI_KTime)); end; end; end; end; end; end; finally l_WMILocator := nil; l_WMIServices := nil; end; Memo1.Lines.EndUpdate; end; |
Re: Memory-Leak WMI
So, vorerst das letzte Update, bin am Ende mit meinem Latein.
Hab das Ganze mal unter Windows XP Media Center Edition SP2 getestet. Resultat : Auch das selbe Memory-Leak. Also wenn hier keiner ne Idee hat harke ich das Thema WMI einfach ab. Hab ja kein Problem damit eigene Fehler zu suchen, aber auf Microsoft's Fehler hab ich leider keinen Einfluss. MfG El-Blindo. |
Re: Memory-Leak WMI
Moin El-Blindo,
mir fällt nur auf, dass Du zwar das Memo löscht, aber dann zu Liste Zeilen hinzufügst. Das solltest Du vielleicht mal in Einklang bringen ;-) Ausserdem könntest Du mal zu Beginn der Routine den Timer ab, und am Ende wieder einschalten. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:32 Uhr. |
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