Ho creato uno script PowerShell che scorre su un numero elevato di file XML Schema (.xsd) e crea ciascuno un oggetto .NET XmlSchemaSet
, chiama Add()
e Compile()
per aggiungervi uno schema e stampa tutti gli errori di convalida.Come istruire PowerShell a raccogliere oggetti .NET come XmlSchemaSet?
Questo script funziona correttamente, ma c'è una perdita di memoria da qualche parte, causando il consumo di gigabyte di memoria se eseguito su centinaia di file.
Quello che in sostanza fare in un ciclo è la seguente:
$schemaSet = new-object -typename System.Xml.Schema.XmlSchemaSet
register-objectevent $schemaSet ValidationEventHandler -Action {
...write-host the event details...
}
$reader = [System.Xml.XmlReader]::Create($schemaFileName)
[void] $schemaSet.Add($null_for_dotnet_string, $reader)
$reader.Close()
$schemaSet.Compile()
(uno script completo per riprodurre il problema può essere trovato in questo gist:. https://gist.github.com/3002649 Basta eseguirlo, e guardare l'aumento dell'utilizzo della memoria in Task manager o Process Explorer.)
Ispirato da alcuni post del blog, ho provato ad aggiungere
remove-variable reader, schemaSet
ho provato anche raccogliendo la $schema
fro m Add()
e facendo
[void] $schemaSet.RemoveRecursive($schema)
Questi sembrano avere qualche effetto, ma ancora non v'è una perdita. Presumo che le precedenti istanze di XmlSchemaSet
utilizzino ancora la memoria senza essere raccolte in modo inutile.
La domanda: Come faccio a insegnare correttamente al garbage collector che può recuperare tutta la memoria utilizzata nel codice sopra? O più in generale: come posso raggiungere il mio obiettivo con una quantità limitata di memoria?
Questo rende l'aumento inferiore, quindi questo può essere d'aiuto nella pratica; ma la quantità di memoria utilizzata sta ancora aumentando gradualmente. –
aggiungendo un '$ reader.Dispose()' dopo averlo chiuso aiuta di più? –
Come descritto in [un'altra risposta StackOverflow] (http://stackoverflow.com/a/745965/223837) questo non è direttamente possibile in PowerShell e non è necessario perché 'Chiudi()' implica un 'Dispose()' come da convenzione Microsoft raccomandata. –