Freeing up memory in PowerShell using garbage collector

Just got this great tip from Lars on how he reduces memory consumption in his AD PowerShell scripts with a simple garbage collection call (basically explicitly telling .NET behind PowerShell to recycle the objects no longer in use):

Using Quest AD tools I often run in to memory consumption problems. I thought it was a question of memoryleaks, but its not, its the Garbage collection that doesn’t get collection until its to late.
So i’m using this when I use Quests AD Management Cmdlets in PowerShell, where $i is a simple counter

if (($i % 200) -eq 0)
{
[System.GC]::Collect()
}

Hope that helps!

9 Responses to “Freeing up memory in PowerShell using garbage collector”


  1. 1 Kelvin Wong February 25, 2012 at 6:45 pm

    Reblogged this on Salt * Wet * Bytes and commented:
    Something new and useful to remember 🙂

  2. 2 Ashutosh February 29, 2012 at 9:29 am

    Explicitly calling Garbge collector is not a good idea generally. The garbace collector is optimized to run at specific intervals depending on memory usage. Manually calling the GC disturbs the calculation,

    • 3 Dmitry Sotnikov February 29, 2012 at 3:14 pm

      Indeed one should use caution: in your particular case resulting performance may get better or worse. In this particular situation though, one of the users reported that he is getting much lower memory consumption when in between his AD management with PowerShell inside PowerGUI Script Editor he is using garbage collection calls – so I wanted to pass the knowledge.

  3. 4 bethrobertswproute July 30, 2016 at 1:05 am

    There are good reasons to run the garbage collector explicitly on an occasional basis. The GC runs on a separate thread and will only operate on objects of a .NET process when the process thread yields. If a process does not yield then the GC will not run and the process can crash with an out of memory exception.

    This can happen (does happen to my processes) when I run long running tasks via a scheduled task. It took me a while to realise why a process run in the PoSh GUI always worked but would fail when run as a scheduled task.

    Hindsight being a wonderful thing, its now obvious that when a process is run in a GUI the process itself is run on a background thread and the GUI thread will periodically yield (because that’s what GUIs do) giving the GC chance to work.

    When the same script is run as a scheduled task there is nothing to cause the scheduled task thread to yield so the GC never has an opportunity to work.

    The solution is to call [System.GC]::Collect() and then the sleep cmdlet for a few milliseconds. Calling sleep is important because this causes the process thread to yield giving the GC the opportunity it needs to work,

    • 5 SassDawe May 20, 2019 at 11:47 am

      I’m not sure how can I add this to my script which is running multiple background threads parallel using runspaces.
      Should I add it to all of them or only add it to one of them? Do I have to start a sleep step in all threads to yield?
      Thanks

  4. 6 Jeremy Saunders September 21, 2017 at 8:42 pm

    I have been using [System.GC]::Collect() successfully for years, but am intrigued with the modulo operator used here.

    if (($i % 200) -eq 0)

    I would just use…

    if ($i -eq 200)

    Does it matter?

    Cheers,
    Jeremy

    • 7 Dustin Saunders March 8, 2018 at 9:40 am

      Yes– modulo is used for an “every x iterations” in this scenario. In your case you’d have to set $i = 0 at some point. Neither is right nor wrong, but if you are using $i as something like a progress bar you’d lose your place or would have to create a new variable just for that which would be wasteful.

  5. 8 Jon Czerwinski (@JonCzerwinski) January 30, 2018 at 3:50 am

    Jeremy,

    In your example, GC would only run once, at 200 items, and either never again, or you’re resetting $i to 0 and counting back up. Your $i would only be used to track when you wanted GC to run.

    Dmitry’s using $i as a counter. Presumably elsewhere he’s reporting progress or at the end reporting total objects processed. The use of modulus here is so every 200 objects, he runs garbage collection. He’s getting his trigger for free as a side effect.


  1. 1 PoSH Garbage Collection « Lange's Tech Musings Trackback on February 29, 2012 at 8:04 pm

Leave a comment




Legal

The posts on this blog are provided “as is” with no warranties and confer no rights. The opinions expressed on this site are mine and mine alone, and do not necessarily represent those of my employer - WSO2 or anyone else for that matter. All trademarks acknowledged.

© 2007-2014 Dmitry Sotnikov

February 2012
M T W T F S S
 12345
6789101112
13141516171819
20212223242526
272829