Start-Sleep 内存泄漏(或导致 powershell 内存泄漏)?

jia*_*gok 0 powershell

这个问题来自https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/365ca396-400d-4401-bd7f-05d5d6c22cc8/powershells-startsleep-causes-memory-growth?forum=winserverpowershell

我在那里没有得到有效的答案,所以试试这个论坛是否可以提供帮助。这阻碍了我的工作。

这是我的两个 powershell 脚本。第一个是创建事件源,第二个是使用 4 个线程生成事件。每个线程中使用 Start-Sleep 来控制事件生成率。如果我删除 Start-Sleep,那么 powershell 内存使用量是恒定的,否则它会快速增长,直到使用完所有系统内存并且系统变得非常慢。

这是一个已知的问题?任何解决方法?欣赏任何线索。

# use this script to create channel and source if they does not exist.

$logName = "TestLog"
$sourceName = "TestSource"

New-EventLog -LogName $logName -Source $sourceName

# maximumSize's max is 4G.
Limit-EventLog -LogName $logName -OverflowAction OverWriteOlder -RetentionDays 30 -MaximumSize 3080000KB
Run Code Online (Sandbox Code Playgroud)

事件生成脚本:

# use this script to generate events in TestLog channel.

Param(
  [int]$sleepIntervalInMilliSeconds = 0
)

$eventGenScript = {
  $logName = "TestLog"
  $sourceName = "TestSource"

  while($true) {
    Write-EventLog -LogName $logName -Source $sourceName -Message "perfLog" -EventId 0 -EntryType information
    Start-Sleep -ms $sleepIntervalInMilliSeconds
  }
}

$threadCount = 4

for($i=0; $i -lt $threadCount; $i++)
{
  Start-Job $eventGenScript  
}

read-host "type a key to exit. You need to wait for some time for threads to exit."
Run Code Online (Sandbox Code Playgroud)

Ans*_*ers 5

这不是Start-Sleep内存泄漏,您使用无效参数 ( -ms)调用它,并且作业的进程内存充满错误消息,因为您一直在无限循环中调用(无效)语句。

示范:

PS C:\> Start-Sleep -ms 100
Start-Sleep : A parameter cannot be found that matches parameter name 'ms'.
At line:1 char:13
+ Start-Sleep -ms 100
+             ~~~
    + CategoryInfo          : InvalidArgument: (:) [Start-Sleep], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.StartSleepCommand
Run Code Online (Sandbox Code Playgroud)

此外,您在$sleepIntervalInMilliSeconds脚本块外部定义,但尝试在脚本块内部使用它,这是行不通的,因为该变量在脚本块范围内未定义。这就是为什么尽管您在 Microsoft 论坛上获得了正确的建议,但您的问题仍然存在。

PS C:\> $ms = 100
PS C:\> $job = Start-Job -ScriptBlock { Start-Sleep -Milliseconds $ms }
PS C:\> $job | Wait-Job | Receive-Job
Cannot validate argument on parameter 'Milliseconds'. The argument is null,
empty, or an element of the argument collection contains a null value.
Supply a collection that does not contain any null values and then try the
command again.
    + CategoryInfo          : InvalidData: (:) [Start-Sleep], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartSleepCommand
    + PSComputerName        : localhost
Run Code Online (Sandbox Code Playgroud)

您有三种选择来处理这个问题:

  • 在脚本块内定义变量:

    PS C:\> $job = Start-Job -ScriptBlock {
    >> $ms = 100
    >> $ms
    >> Start-Sleep -Milliseconds $ms
    >> }
    >>
    PS C:\> $job | Wait-Job | Receive-Job
    100
    Run Code Online (Sandbox Code Playgroud)
  • 使用using范围修饰符获取局部变量:

    PS C:\> $ms = 100
    PS C:\> $job = Start-Job -ScriptBlock {
    >> $using:ms
    >> Start-Sleep -Milliseconds $using:ms
    >> }
    >>
    PS C:\> $job | Wait-Job | Receive-Job
    100
    Run Code Online (Sandbox Code Playgroud)
  • 将变量作为参数传递到脚本块中:

    PS C:\> $ms = 100
    PS C:\> $job = Start-Job -ScriptBlock {
    >> param($ms)
    >> $ms
    >> Start-Sleep -Milliseconds $ms
    >> } -ArgumentList $ms
    >>
    PS C:\> $job| Wait-Job | Receive-Job
    100
    Run Code Online (Sandbox Code Playgroud)

底线:替换

Start-Sleep -ms $sleepIntervalInMilliSeconds
Run Code Online (Sandbox Code Playgroud)

Start-Sleep -Milliseconds $using:sleepIntervalInMilliSeconds
Run Code Online (Sandbox Code Playgroud)

问题就会消失。