Задать вопрос
@conJOULA

Скрипт powershell использует слишком много памяти. Что я делаю не так?

Windows 10. PowerShell 7.4.4. Имеется следующий простой скрипт, для примера проблемы, которую я пытаюсь понять:
$threadslimit = 8
$collection = @{}
$synccollection = [System.Collections.Hashtable]::Synchronized($collection)

1..1000 | ForEach-Object {
    $data = @('some', 'valuable', 'text', 'data')
    $synccollection.Add($_, $data)
}

#выводим созданную коллекцию до изменений, просто чтобы можно было сравнить
$synccollection

# Массив ключей для обхода коллекции
$keys = @($synccollection.Keys)

$jobs = @()

foreach ($key in $keys) {
    $jobs += Start-ThreadJob -ScriptBlock {
        param(
            $synccollection,
            $key
        )

        # Здесь на самом деле какая-то функция, которая возвращает строку
        $format = 'Changed data'

        # Изменяем одно из полей, напоминаю, по ключам лежат массивы
        $synccollection[$key][3] = $format

        # Тут вывод чтобы просто отслеживать выполнение скрипта
        Write-Output "Data was changed"

    } -ThrottleLimit $threadslimit -ArgumentList $synccollection, $key
}

foreach ($job in $jobs) {
    $results = Receive-Job -Job $job -Wait
    Write-Host "Job $($job.Name) - $results"
    Remove-Job -Job $job
}

# Вывод самой коллекции в консоль, чтобы убедиться, что значения поменялись
$synccollection


Скрипт вроде работает как надо, но после первого же запуска, память которую занимает процесс pwsh увеличивается в разы:
66b258f5d801e115268281.jpeg
Вот столько процесс занимал до запуска скрипта:
66b2591a8ca89764198451.jpeg

Часть памяти удается освободить при помощи [System.GC]::Collect(), но даже с ним, процесс все ещё остается сильно раздутым:
66b25956d74c0401378249.jpeg
Get-Jobs пустой, если закрыть pwsh, память сразу же освобождается. Размер самой коллекции явно не такой большой, чтобы занимать 1+ГБ оперативки. Что я делаю не так, нагуглить/начатгптиить ответ не получилось.
  • Вопрос задан
  • 384 просмотра
Подписаться 1 Простой Комментировать
Решения вопроса 1
@conJOULA Автор вопроса
Удалось добиться желаемого поведения использовав другой подход (другую фичу), которая называется ForEach-Object -Parallel. Если кто-то случайно забредёт сюда в поисках ответа, можете попробовать следующее:

$threadslimit = 8
$collection = @{}
$synccollection = [System.Collections.Hashtable]::Synchronized($collection)

1..1000 | ForEach-Object {
    $data = @('some', 'valuable', 'text', 'data')
    $synccollection.Add($_, $data)
}

#выводим созданную коллекцию до изменений, просто чтобы можно было сравнить
$synccollection

$keys = @($synccollection.Keys)

$keys | ForEach-Object -Parallel {
    $synccollectionscope = $using:synccollection

    # Здесь на самом деле какая-то функция, которая возвращает строку
    $format = 'Changed data'

    # Изменяем одно из полей, напоминаю, по ключам лежат массивы
    $synccollectionscope[$_][3] = $format

    # Тут вывод чтобы просто отслеживать выполнение скрипта
    Write-Output "Data was changed"

} -ThrottleLimit $threadslimit

# Вывод самой коллекции в консоль, чтобы убедиться, что значения поменялись
$synccollection


Делает то же самое, использует практически нулевое количество памяти, работает быстрее.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы