Skip to content

Instantly share code, notes, and snippets.

@haxtibal
Created March 22, 2022 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haxtibal/69c9559a109f09a1f19c76cc3b026c81 to your computer and use it in GitHub Desktop.
Save haxtibal/69c9559a109f09a1f19c76cc3b026c81 to your computer and use it in GitHub Desktop.
Try to reproduce memory leak as in icinga-powershell-framework
# Add this file as module to your PSModulePath, call Test-Leak in an interactive PS session,
# and watch the managed heap size in a debugger session
$Global:Vars = [hashtable]::Synchronized(@{});
$Global:Vars.Add('WorkerQueues', @{});
function Producer {
param (
$ThreadId = 0
)
Write-Host ("enter producer thread {0}" -f $ThreadId);
$WorkerThreadId = 0;
while ($TRUE) {
$workload = new-object byte[] 84000; # smaller than LOH threshold
$Global:Vars.WorkerQueues.($WorkerThreadId % 2).Enqueue($workload);
$WorkerThreadId += 1;
Start-Sleep -Milliseconds 10;
}
}
function Consumer()
{
param (
$ThreadId = 0
)
Write-Host ("enter consumer thread {0}" -f $ThreadId);
while ($TRUE) {
if ($Global:Vars.WorkerQueues.$ThreadId.Count -eq 0) {
Start-Sleep -Milliseconds 10;
continue;
}
$workload = $Global:Vars.WorkerQueues.$ThreadId.Dequeue();
}
}
function Set-GlobalEnvironment()
{
param (
$GlobalEnvironment = $null
);
$Global:Vars = $GlobalEnvironment;
}
function New-ThreadInstance()
{
param (
$ThreadId = 0,
[string]$Command = ''
);
$Shell = [PowerShell]::Create();
$RunSpaces = [RunSpaceFactory]::CreateRunSpacePool(1, 1,
[System.Management.Automation.RunSpaces.InitialSessionState]::CreateDefault(), $host
)
$RunSpaces.Open();
$Shell.RunSpacePool = $RunSpaces;
[void]$Shell.AddCommand('Set-GlobalEnvironment');
[void]$Shell.AddParameter('GlobalEnvironment', $Global:Vars);
[void]$Shell.AddCommand($Command);
[void]$Shell.AddParameter('ThreadId', $ThreadId);
$Result = $Shell.BeginInvoke();
}
function Test-Leak {
$ThreadId = 0;
$ConcurrentThreads = 5;
while ($ConcurrentThreads -gt 0) {
$ConcurrentThreads = $ConcurrentThreads - 1;
[System.Collections.Queue]$WorkerQueue = @();
$Global:Vars.WorkerQueues.Add($ThreadId, [System.Collections.Queue]::Synchronized($WorkerQueue));
New-ThreadInstance -Command 'Consumer' -ThreadId $ThreadId;
$ThreadId += 1;
}
New-ThreadInstance -Command 'Producer';
while ($true) {
Start-Sleep 1;
}
}
Export-ModuleMember -Alias * -Function * -Variable *;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment