Проблема с потреблением памяти задания Powershell

Я боролся с этим уже неделю и исчерпал все методы и варианты, которые нашел в Интернете. Я надеюсь, что кто-то здесь сможет помочь мне с этим.

Я использую powershell для запуска 8 заданий, каждое задание запускает FFmpeg для потоковой передачи 7-минутного файла на удаленный RTMP-сервер. Это извлечение из файла на диске, и каждое задание использует другой файл. Команда находится в цикле do while, поэтому она постоянно перезагружается.

Это приводит к тому, что оболочка, из которой я запускал задания, накапливает огромный объем памяти, потребляя все, что может. За 24 часа он потреблял 30 из 32 ГБ моего сервера.

Вот мой код запуска, буду признателен за любую помощь.

start-job -Name v6 -scriptblock {
do { $d = $true; $f = Invoke-Expression -Command "ffmpeg -re -i `"C:\Shares\Matthew\180p_3000k.mp4`" -vcodec copy -acodec copy -f flv -y rtmp://<ip>/<appName>/<streamName>"; $f = $null }
while ($d = $true)

}

Я пытался получить задания и передать их в out-null, я пытался установить для $f значение $null перед запуском цикла do while и некоторые другие вещи, которые я нашел в Интернете, но безрезультатно. Спасибо всем за ваше время!


person Matt Wall    schedule 30.03.2015    source источник
comment
сделать { } пока ($d = $true)   -  person Jan Chrbolka    schedule 31.03.2015
comment
do { } while ($d = $true) — бесконечный цикл. Ваше выражение будет вызываться снова и снова и снова.... Если вы хотите проверить условие do while ($d -eq $true) Затем снова 'do { $d = $true; } while ($d -eq $true)' также является бесконечным циклом, если вы где-нибудь не установили $d в $false. Что-то у вас с логикой не так. Можете ли вы попытаться облечь логику в слова в своем вопросе? Постоянно репостишь? Или повторный поток, когда один поток заканчивается?   -  person Jan Chrbolka    schedule 31.03.2015
comment
О, чувак, я снова совершил глупую ошибку. Я изменю это на $d -eq $true, но это должно быть бесконечное количество. Когда 7-минутный клип заканчивается, он должен просто повторить его снова. Может быть, мне не следует делать бесконечный цикл и ждать завершения задания и переделывать задание?   -  person Matt Wall    schedule 31.03.2015
comment
Просто любопытно, пробовали ли вы Remove-Variable F?   -  person Booga Roo    schedule 01.04.2015


Ответы (2)


Лучше поздно, чем никогда, я думаю. У меня была такая же проблема с огромным потреблением памяти при запуске ffmpeg в заданиях Powershell. Суть проблемы заключается в том, что задание Powershell будет сохранять любой/все выходные данные в памяти, а ffmpeg очень рад регистрировать выходные данные как в стандартном потоке output, так и в стандартном потоке error.

Мое решение состояло в том, чтобы добавить параметр «-loglevel quiet» в ffmpeg. В качестве альтернативы вы можете перенаправить как стандартный поток, так и поток ошибок на null (недостаточно перенаправить только стандартный поток). Подробнее о том, как перенаправить стандартные потоки, см. в этом вопросе: Перенаправление стандартного вывода и вывода ошибок в один и тот же файл журнала

person Helge Elvik    schedule 14.07.2016
comment
Спасибо, это было полезно! Я собираюсь попробовать это. Обходной путь, который у меня был в течение некоторого времени, заключался в том, чтобы запихнуть команды ffmpeg в пакетные файлы. Если бы мне нужно было быть динамичным, я бы написал команды в виде пакетного файла и запускал их из сценария. Вроде так память не подкрадывалась. Это еще раз доказывает вашу точку зрения - я считаю, что то, что я делал, вызывало определенную степень разделения, чтобы предотвратить пребывание любого stdout или stderr в пространстве имен powershell. - person Matt Wall; 07.08.2016

Существует много способов вызвать скрипт или выражение PowerShell.

Одним из моих любимых является использование RunspacePool. В RunspacePool каждая задача запускается с новым пространством выполнения. Когда задача завершается, пространство выполнения удаляется. Это должно поддерживать довольно постоянное потребление памяти. Это не самый простой способ разобраться, но вот простой пример, который может сработать для вас.

$Throttle = 10 # Maximum jobs that can run simultaneously in a runpool
$maxjobs = 8 # Maximum jobs that will run simultaneously
[System.Collections.ArrayList]$jobs = @()
$script:currentjobs = 0
$jobindex = 0
$jobaction = "ffmpeg -re -i `"C:\Shares\Matthew\180p_3000k.mp4`" -vcodec copy -acodec copy -f flv -y rtmp://<ip>/<appName>/<streamName>"

$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspace = [runspacefactory]::CreateRunspacePool(1, $Throttle, $sessionstate, $Host)
$runspace.Open()


function QueueJob{
    param($jobindex)
    $job = "" | Select-Object JobID,Script,Errors,PS,Runspace,Handle
    $job.JobID = $jobindex
    $job.Script = $jobaction
    $job.PS = [System.Management.Automation.PowerShell]::create()
    $job.PS.RunspacePool = $runspace
    [void]$job.PS.AddScript($job.Script)
    $job.Runspace = $job.PS.BeginInvoke()
    $job.Handle = $job.Runspace.AsyncWaitHandle
    Write-Host "----------------- Starting Job: $("{0:D4}" -f $job.JobID) --------------------" -ForegroundColor Blue
    $jobs.add($job)
    $script:currentjobs++
}

Function ServiceJobs{
    foreach($job in $Jobs){
        If ($job.Runspace.isCompleted) {
            $result = $job.PS.EndInvoke($job.Runspace)
            $job.PS.dispose()
            $job.Runspace = $null
            $job.PS = $null
            $script:currentjobs--
            Write-Host "----------------- Job Completed: $("{0:D4}" -f $job.JobID) --------------------" -ForegroundColor Yellow
            Write-Host $result
            $Jobs.Remove($job)
            return
        }
    }
}

while ($true) {
    While ($script:currentjobs -le $maxjobs){
        QueueJob $jobindex
        $jobindex++
    }
    ServiceJobs
    Start-Sleep 1
}

$runspace.Close()
[gc]::Collect() 

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

person Jan Chrbolka    schedule 01.04.2015
comment
Я только что увидел это - спасибо - я попытаюсь понять, как это использовать. Мне нравится эта идея, и я думаю, что моим фактическим решением этой проблемы было то, что я как бы косвенно запускал ffmpeg в новом пространстве имен, запуская его через вызов динамически написанных пакетных файлов. - person Matt Wall; 07.08.2016