Memory leaks 用于监视系统性能和内存泄漏的VBscript

Memory leaks 用于监视系统性能和内存泄漏的VBscript,memory-leaks,vbscript,Memory Leaks,Vbscript,我有一个简单的脚本,可以在循环中监视Windows XP中进程的不同性能统计信息,直到终止。 尽管我做了很多努力,脚本的内存占用还是会随着时间的推移而增加。 非常感谢您的建议 Set fso = CreateObject("Scripting.FileSystemObject") logFileDirectory = "C:\POSrewrite\data\logs" Dim output Dim filePath filePath = "\SCOPerformance-" &

我有一个简单的脚本,可以在循环中监视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

我认为脚本的主要问题是在循环中初始化WMI对象,即在循环的每次迭代中,即使这些对象始终相同:

strComputer = "."
Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
Set objServicesCimv2 = GetObject("winmgmts:\\" _
    & strComputer & "\root\cimv2")
Set objRefreshableItem = _
    objRefresher.AddEnum(objServicesCimv2 , _
    "Win32_PerfFormattedData_PerfProc_Process")
您需要将此代码移出循环,例如,在脚本的开头


其他提示和建议:

  • 使用并显式声明脚本中使用的所有变量。声明的变量比未声明的变量稍快

  • 用于组合路径的多个部分。这个方法的有用之处在于它为您插入了必要的路径分隔符

    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
    

我建议不要在脚本中的永久循环中运行脚本,除非您确实需要这样一个紧密的循环。我建议在脚本中进行一次迭代,称为“来自计划任务”。

在本文中,Eric Lippert(在Microsoft从事VBScript的设计和构建)指出,处理事情的顺序可能很重要。也许你遇到了这样的错误

我会让你读剩下的


我遇到了完全相同的问题,将其用于procmon风格的尝试,以捕获似乎正在重生的恶意进程

缩小范围来看,它似乎是对象refresher.Refresh,根本没有办法解决它

为了克服这个问题,我使用了一个for…next来运行它100次,然后立即运行以下命令,这将使脚本重新启动并关闭:

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

所以我会看着内存从5Mb爬升到40Mb,然后再下降到5Mb

谢谢你的及时和详细的回复,Helen。我已尝试将WMI对象移出循环,但我看到的日志输出不一致(缺少进程,for循环中跳过了迭代)。将这些对象移出循环可以显著降低内存泄漏的速度,但它仍然会增长,尽管速度很慢。再次感谢你的帮助。+1这是一个非常详细的答案,值得投票表决。如果可以的话,我已经不止一次地投了赞成票。哇,那真是一篇很棒的文章。我承认从别人糟糕的代码中通过示例学习了VBScript,正如Eric所描述的那样。我总是觉得你必须将变量设置为零(可能)某种COM分配的资源,但很高兴知道事实并非如此,真正的原因是什么。谢谢你!