2010-08-12 2 views
3

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

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 

ответ

3

Я думаю, что главная проблема с вашим сценарием является то, что вы инициализировать объекты 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

Спасибо за ваш быстрый и подробный ответ, Хелен. Я попытался перемещать объекты WMI за пределы цикла, но вывод журнала, который я вижу, противоречив (процессы отсутствуют, итерации пропущены в цикле for). Перемещение этих объектов за пределы цикла замедлило утечку памяти, но она все еще растет, хотя и медленно. Еще раз спасибо за помощь. – Ben

+1

+1 Это очень подробный ответ, заслуживающий поддержки. Я проголосовал за него не один раз, если мог. – Terrance

0

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

3

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

Я дам вам читать остальное ...

When Are You Required To Set Objects To Nothing?

+0

Вау, это действительно замечательная статья. Я признаю, что изучил VBScript на примере чужого ужасного кода, точно так же, как описал Эрик. Мне всегда казалось, что вам нужно было установить переменные на ничего, что было (возможно) каким-то ресурсом, выделенным COM, но приятно знать, что это не так, и что такое настоящая аргументация. Спасибо за это! – Kilanash

+0

Да, я узнал то же самое. ;) – mpeterson

0

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

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

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

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

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

Смежные вопросы