WMI Memory Leaks

  • Hi,

    ich möchte noch einmal auf das Thema Memory Leaks durch WMI Objekte kommen. Gibt es mittlerweile einen Workaround? Man schaue sich dazu folgendes Skript an:

    Spoiler anzeigen
    [autoit]

    While 1
    _OSSerialNumber()
    Sleep(1000)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _OSSerialNumber()
    Local $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    Local $colSettings = $objWMIService.ExecQuery ("Select SerialNumber from Win32_OperatingSystem")
    For $objOperatingSystem In $colSettings
    $objWMIService = 0
    Return ($objOperatingSystem.SerialNumber & '"')
    Next
    EndFunc ;==>_OSSerialNumber

    [/autoit]

    Die Zeile

    [autoit]

    $objWMIService = 0

    [/autoit]

    kann man sich auch sparen, bringt überhaupt nichts. Wenn man die AU3 nun kompiliert und laufen lässt, sieht man, dass sich der Speicherverbrauch kontinuierlich erhöht. Das ist natürlich völlig inakzeptabel und WMI ist so nicht für mich zu gebrauchen.

    Liegt das Problem an WMI oder an AutoIt (fehlerhafte Implementierung der Object-Functions)?

    Bin für jeden Vorschlag zu haben!

    PS: Sehe anhand meines Beispiels, dass die Synatx hervorhebung für Objekt-Methoden nicht richtig ist, dass nur nebenbei! :D

    EDIT: Habe auch folgendes probiert, aber auch kein Unterschied (Hätte ja sein können, das es am wiederholten Aufruf von ObjGet liegt, scheint aber mehr an den Queries zu liegen:

    Spoiler anzeigen
    [autoit]

    main()

    [/autoit] [autoit][/autoit] [autoit]

    Func OnAutoItStart()
    Opt("MustDeclareVars", 1)
    EndFunc ;==>OnAutoItStart

    [/autoit] [autoit][/autoit] [autoit]

    Func main()
    Local $objWMIService = _WMIInit()

    While 1
    _OSSerialNumber($objWMIService)
    Sleep(1000)
    WEnd
    EndFunc ;==>main

    [/autoit] [autoit][/autoit] [autoit]

    Func OnAutoItExit()
    GUIDelete()
    EndFunc ;==>OnAutoItExit

    [/autoit] [autoit][/autoit] [autoit]

    Func _OSSerialNumber(ByRef Const $objWMIService)
    Local $colSettings = $objWMIService.ExecQuery ("Select SerialNumber from Win32_OperatingSystem")
    For $objOperatingSystem In $colSettings
    Return ($objOperatingSystem.SerialNumber & '"')
    Next
    EndFunc ;==>_OSSerialNumber

    [/autoit] [autoit][/autoit] [autoit]

    Func _WMIInit()
    Return (ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2"))
    EndFunc ;==>_WMIInit

    [/autoit]


    Das nervt mich ab. Mann kann zwar dadurch Dinge einmalig abfragen (was ja auch oftmals reicht), wirklich dynamische Sachen sind so aber nicht durchführbar!

    Einmal editiert, zuletzt von teh_hahn (23. Oktober 2007 um 21:49)

  • Hm sieht mir sehr nach einem AutoIt-internen Bug aus.
    Das Objekt ist nur lokal deklariert und müsste folglich mit jeder Beendigung der Funktion aus dem Speicher verschwinden. - tut es ja bekanntlich aber nicht.
    Wär wohl eine Meldung an die AutoIt-Developer wert.

    Bis dahin kannst du dir das Skript so umschreiben das das Objekt nur einmal erzeugt wird - die Daten des Objekts sollten dennoch dynamisch bleiben:

    Spoiler anzeigen
    [autoit]

    Global $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    ConsoleWrite(_OSSerialNumber() & @CRLF)
    Sleep(1000)
    WEnd

    Func _OSSerialNumber()
    Local $e

    For $e In $objWMIService.ExecQuery ("Select SerialNumber from Win32_OperatingSystem")
    Return $e.SerialNumber
    Next
    EndFunc

    [/autoit]
  • Also bei mir funktioniert IsObj().
    Zeigt bei beiden Objekten korrekt 1 an.
    Auch ObjName funktioniert bei mir problemlos.

    Edit: War mir nicht ganz sicher ob die Daten tatsächlich dynamisch bleiben auch wenn das WMI-Objekt nur einmal erzeugt wird.
    So sollte es aber dann wirklich dynamisch bleiben (Wird man bei der BS-Seriennummer aber wohl kaum bemerken... ;)):

    Spoiler anzeigen
    [autoit]

    Global $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    ConsoleWrite(_OSSerialNumber($objWMIService) & @CRLF)
    Sleep(1000)
    WEnd

    Func _OSSerialNumber(ByRef $WMIObject)
    Local $e
    For $e In $WMIObject.ExecQuery ("Select SerialNumber from Win32_OperatingSystem")
    $e.Refresh_
    Return $e.SerialNumber
    Next
    EndFunc

    [/autoit]


    Edit 2: Hab noch eine kleine Beobachtung gemacht.
    Wenn das Skript gestartet wird wird im Hintergrund logischerweise auch der Prozess wmiprvse.exe gestartet welcher den WMI-Dienst darstellt.
    Allerdings bleibt dieser Prozess auch weiterhin nach dem Beenden des Skriptes bestehen.

    2 Mal editiert, zuletzt von AspirinJunkie (24. Oktober 2007 um 11:10)