VBscript для мониторинга производительности системы утечки памяти - PullRequest
3 голосов
/ 12 августа 2010

У меня есть простой скрипт, который отслеживает различную статистику производительности процессов в Windows XP в цикле, пока он не завершится.
Несмотря на мои усилия, объем памяти скрипта со временем увеличивается.
Любой совет с благодарностью.

    Set fso = CreateObject("Scripting.FileSystemObject")
logFileDirectory = "C:\POSrewrite\data\logs"
Dim output
Dim filePath

filePath = "\SCOPerformance-" & Day(Now()) & Month(Now()) & Year(Now()) & ".log"

IF fso.FolderExists(logFileDirectory) THEN

ELSE
    Set objFolder = fso.CreateFolder(logFileDirectory)
END IF

logFilePath = logFileDirectory + filePath + ""

IF (fso.FileExists(logFilePath)) THEN
    set logFile = fso.OpenTextFile(logFilePath, 8, True)
    output = VBNewLine
    output = output & (FormatDateTime(Now()) + " Open log file." & VBNewLine)

ELSE
    set logFile = fso.CreateTextFile(logFilePath)
    output = output & (FormatDateTime(Now()) + " Create log file." & VBNewLine)
END IF

output = output & (FormatDateTime(Now()) + " Begin Performance Log data." & VBNewLine)
output = output & ( "(Process) (Percent Processor Time) (Working Set(bytes)) (Page Faults Per Second) (PrivateBytes) (PageFileBytes)" & VBNewLine)

WHILE (True)
    On Error Resume NEXT
    IF Err = 0 THEN 

        strComputer = "."
        Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
        Set objServicesCimv2 = GetObject("winmgmts:\\" _
            & strComputer & "\root\cimv2")
        Set objRefreshableItem = _
            objRefresher.AddEnum(objServicesCimv2 , _
            "Win32_PerfFormattedData_PerfProc_Process")
        objRefresher.Refresh
        ' Loop through the processes three times to locate  
        '    and display all the process currently using 
        '    more than 1 % of the process time. Refresh on each pass.

        FOR i = 1 TO 3

            objRefresher.Refresh 
            FOR Each Process in objRefreshableItem.ObjectSet
                IF Process.PercentProcessorTime > 1 THEN
                    output = output & (FormatDateTime(Now()) & "," &  i ) & _
                        ("," & Process.Name & _
                        +","  & Process.PercentProcessorTime & "%") & _
                        ("," & Process.WorkingSet) & ("," & Process.PageFaultsPerSec) & _
                        "," & Process.PrivateBytes & "," & Process.PageFileBytes & VBNewLine
                END IF
            NEXT
        NEXT
    ELSE
            logFile.WriteLine(FormatDateTime(Now()) + Err.Description)
    END IF
    logFile.Write(output)
    output = Empty
    set objRefresher = Nothing
    set objServicesCimv2 = Nothing
    set objRefreshableItem = Nothing
    set objFolder = Nothing
    WScript.Sleep(10000)
Wend

Ответы [ 4 ]

3 голосов
/ 27 августа 2010

В этой статье Эрик Липперт (буквально работавший над проектированием и сборкой VBScript в Microsoft) указывает, что порядок, в котором вы распоряжаетесь вещами, может быть важным. Может быть, вы столкнулись с одной из этих ошибок?

Я дам тебе прочесть остальное ...

Когда вы должны устанавливать объекты в ничего?

3 голосов
/ 12 августа 2010

Я думаю, что основная проблема вашего скрипта в том, что вы инициализируете объекты WMI внутри цикла, то есть на каждой итерации цикла, даже если эти объекты всегда одинаковы:

strComputer = "."
Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
Set objServicesCimv2 = GetObject("winmgmts:\\" _
    & strComputer & "\root\cimv2")
Set objRefreshableItem = _
    objRefresher.AddEnum(objServicesCimv2 , _
    "Win32_PerfFormattedData_PerfProc_Process")

Вынеобходимо вывести этот код из цикла, например, в начало скрипта.

Другие советы и предложения:

  • Используйте Option Explicit и явно объявите все переменные, используемые в вашем скрипте.Объявленные переменные немного быстрее, чем необъявленные.

  • Используйте FileSystemObject.BuildPath для объединения нескольких частей пути.Полезной особенностью этого метода является то, что он вставляет необходимые вам разделители пути.

    logFileDirectory = "C:\POSrewrite\data\logs"
    filePath = "SCOPerformance-" & Day(Now) & Month(Now) & Year(Now) & ".log"
    logFilePath = fso.BuildPath(logFileDirectory, filePath)
    
  • Переменная objFolder не используется в вашем сценарии, поэтому нет необходимостисоздать это.Кроме того, вы можете сделать проверку FolderExists более читабельной, переписав ее следующим образом:

    If Not fso.FolderExists(logFileDirectory) Then
        fso.CreateFolder logFileDirectory
    End If
    
  • Перемещение повторяющегося кода в подпрограммы и функции для упрощения обслуживания:

    Function DateTime
        DateTime = FormatDateTime(Now)
    End Function
    ...
    output = output & DateTime & " Open log file." & vbNewLine
    
  • Обычно при объединении строк скобки не нужны:

    output = output & DateTime & "," & i & _
        "," & Process.Name & _
        "," & Process.PercentProcessorTime & "%" & _
        "," & Process.WorkingSet   & "," & Process.PageFaultsPerSec & _
        "," & Process.PrivateBytes & "," & Process.PageFileBytes & vbNewLine
    
0 голосов
/ 28 ноября 2017

Я столкнулся с точно такой же проблемой, используя ее для попытки в стиле procmon захватить мошеннический процесс, который, кажется, возрождается.

Сужая все это, оно выглядит как objRefresher.Refresh и, кажется, просто нет пути к этому

Что я сделал, чтобы преодолеть это, так это использовал for ... next, чтобы запустить его 100 раз, а затем сразу же выполнить следующее, котороепросто перезапустил бы скрипт и завершил работу:

CreateObject("Wscript.Shell").Run """" & WScript.ScriptFullName & """", 0, False

Так что я бы наблюдал за ползанием памяти с 5 МБ до 40 МБ, а затем возвращался к 5 МБ

0 голосов
/ 27 августа 2010

Я бы рекомендовал не запускать скрипт в постоянном цикле внутри скрипта, если вам не нужен такой жесткий цикл. Я бы предложил одну итерацию внутри скрипта, вызванную из запланированных задач.

...