2010-09-24 13 views
6

¿Cuál es la forma correcta de eliminar objetos creados dentro de una función? Encontré este método en un sitio web.¿Cómo puedo deshacerme de los objetos de SharePoint de forma segura en las funciones de PowerShell?

function get-spweb ([String]$webUrl=$(throw 'Parameter -webUrl is missing!')) 
{ 
    $site = get-SPSite $weburl 
    return $site.OpenWeb() 
    $site.Dispose() 
} 

¿Alguna vez se llama al método Dispose en esta función?

+0

Si vienes del mundo .NET, no hay nada como "usar". Pero creo que vi algunas solicitudes de funciones en ms connect. – stej

Respuesta

9

En primer lugar, en realidad no desea que aquí se elimine el llamado: cuando llama a Dispose en una instancia de SPSite, todos los webs devueltos a través de su OpenWeb también se eliminan porque son "propiedad" de ese SPSite.

Uno de los modelos utilizados por los cmdlets de SharePoint 2010 es una especie de "eliminación diferida", lo que significa que las instancias de SPWeb no se eliminan hasta que finaliza la interconexión en la que están involucradas. Esto funciona así:

function Get-SPWeb { 
    param([uri]$Url) 

    begin { 
     # get SPSite that owns the passed Url 
     $site = new-object microsoft.sharepoint.spsite $url 
     # return specific SPWeb instance 
     $site.OpenWeb() 
    } 
    end { 
     # this disposes owning spsite AND the returned web 
     $site.Dispose() 
    } 
} 

Ahora aquí es cómo funciona esto en la práctica (se trata de una sola línea):

ps> get-spweb "http://localhost/sites/test" | foreach-object { 
    $_.Title = "New Name"; $_.update() 
} 

La primera parte será obtener una sola SPWeb instancia y pasarlo al ForEach-Object parte. Solo cuando el foreach finalice (y termine de cambiar el título de la web) se llamará al bloque final correspondiente en get-spweb, que dispone el sitio y la web. Lo que es importante es que toda la tubería es un bloque único de código que se ejecuta en una sola llamada.

Esta voluntad no trabajo de forma interactiva como esto:

ps> $w = get-spweb "http://localhost/sites/test" # calls begin AND end 
ps> $w.title = "new name" 
ps> $w.update() # boom! web is already disposed 

Así que en este último ejemplo que tendría que utilizar una aplicación diferente de conseguir-SPWeb (que omite el bloque final, o suprime con un parámetro de cambio) y luego tendría que deshacerse del sitio usted mismo.

Otro detalle importante es que trabajar de forma interactiva en powershell con objetos sharepoint provocará la pérdida de memoria. De forma predeterminada, PowerShell se ejecuta en MTA (apartamento de subprocesos múltiples) y utilizará un conjunto de subprocesos para ejecutar sus comandos. Cada línea ingresada usará un hilo diferente. Cada vez que accede a un objeto COM con un hilo diferente, perderá algo de memoria del montón no administrado, ya que se asigna un nuevo montón para el cambio de contexto (sin que se libere el anterior). Esto se puede aliviar al iniciar powershell.exe con el interruptor -STA. Esto asegurará que todos los comandos y tuberías se ejecuten con el mismo subproceso, evitando la pérdida de memoria. Dicho esto, simplemente cerrar la consola de PowerShell recuperará toda esa memoria nuevamente, pero las secuencias de comandos de ejecución prolongada pueden privar de memoria a los servidores de la memoria si no se tiene cuidado, derribando a SharePoint (a cualquier otra cosa que no le guste perder el trabajo).) Esta es la razón por la que el enfoque de línea única funciona tan bien en el ejemplo anterior: el objeto se asigna y elimina en la misma interconexión y, por extensión, el mismo subproceso. Sin fuga.

+0

¿Cómo encaja esto en 'Start-SPAssignment -Global' –

+0

@Lavinski Con la asignación de inicio/detención, las instancias no se eliminan al final de la ejecución de una tubería. Se eliminan cuando llamas a parar. – x0n

7

No, no lo hace porque debe salir de la función antes de llamar a Dispose. Si usted tiene los recursos que tienen que ser eliminados a continuación, me gustaría utilizar un try/finally así:

$site = Get-SPSite $weburl 
try { 
# do stuff to $site until done with it 
} 
finally { 
    $site.Dispose() 
} 

Lo bueno de fin es que el disponer será llamado no importa lo que salga del bloque try (ya sea con éxito, debido a un error o debido a una declaración de devolución).

Cuestiones relacionadas