If you want to know the top 20 objects associated with the GC Handles that are leaking, you have manual work to do. Think about it:

a)    Run GCHandleLeaks and wait… it’s going to take time.

b)    Get the objects’ instances from the handles.

c)    Count and classify them.

d)    Get the 20 objects that appear most often.

 

Thus, this script saves you time when you need to get this information since it automates these steps.

Of course, it takes time to finish because it runs !sos.GCHandleLeaks and gets the information for each handle. After that, it shows you the top 20 objects leaking.

If you install LogParser, you can get a beautiful chart that shows you the top 20 objects leaking. (great stuff to put in reports J)

 

Note: You have the install the latest PowerDbg version to use this script.

 

Screenshots:

 

 

 

 

 

 

 

 

 

 

Source code for PowerShellScriptGCHandleLeaksChart.ps1:

 

########################################################################################################

# Script:      PowerDbgScriptGCHandleLeaksChart

#

# Parameters:  None.

#

# Purpose:     Shows the top 10 objects associated with GC Handles that are leaking and a graphical view

#              of these objects.

#              Use this script to troubleshoot memory leaks associated with pinned handles, for example.

#

#              Attention! This is for 32 bits.

#

# Usage:       Before running the script:

#              a) Open your workspace to load the symbols.

#              b) .wtitle PowerDbg

#              c) .reload

#              d) .loadby sos mscorwks

#

#              Attention! If you don't load the symbols before running the script you may face timing issues.

#

# Changes History:

#

# Roberto Alexis Farah

# All my functions are provided "AS IS" with no warranties, and confer no rights.

########################################################################################################

set-psdebug -strict

$ErrorActionPreference = "continue"  # Yes, for this script we expect to have handled exceptions.

trap { continue; }

 

write-Host "Verifying potential GC Handle leaks... it's going to take time, you can get a cup of coffee now..." -foreground Green -background Black

 

# Calls !GCHandleLeaks. This command takes A LOT of time to execute.

Send-PowerDbgCommand("!GCHandleLeaks")                              

 

# Extracts output from previous command.

Parse-PowerDbgGCHANDLELEAKS

 

# Converts CSV file to Hash Table.

$output = Convert-PowerDbgCSVtoHashTable

 

write-Host "Done!" -foreground Green -background Black

 

# Verify if there are leaks. If not, notify user and quit.

if($output.Count -eq 1)

{

    # Notifies user the script finished the execution.

    Send-PowerDbgComment "PowerDbgScriptGCHandleLeaks was executed. See the PowerShell window for more information."

 

    write-Host "`n`nThere aren't GC Handles leaking!" -foreground Green -background Black

    return

}

 

# Creates another hash table to stored the objects and the number of times it appears.

$stats = @{}

 

write-Host "Extracting objects from handles..." -foreground Green -background Black

 

# Scans all keys and save the value as the key in another hash table.

foreach($key in $output.keys)

{

    $objAddress = $output[$key]  # The value is the key for the other hash table.

      

    # Use !DumpObj to get the object.

    Send-PowerDbgCommand "!DumpObj $objAddress"

   

    Parse-PowerDbgDUMPOBJ

   

    # Here he get the object mapped to a hash table.

    $objStruct = Convert-PowerDbgCsvToHashTable

    $objName = $objStruct["Name:"]

   

    # If the item is there, increase the number of times it appeared.

    $numberOfTimes = $stats[$objName]

      

    # Verifiy if this is the first time the object is going to be saved.

    if($numberOfTimes -eq $null)

    {

        $stats[$objName] = 1   

    }

    else

    {

        $numberOfTimes++

       

        # Key was there, so increase the number of times it appeared.

        $stats[$objName] = $numberOfTimes

    }

}

 

write-Host "Done!" -foreground Green -background Black

write-Host "Creating CSV files..." -foreground Green -background Black

 

# Prepare string to create CSV file.

$builder = New-Object System.Text.StringBuilder

 

# Title for the CSV fields.

$builder = $builder.AppendLine("ObjectsLeaking,Occurrences")

 

# Scans the hash table that contains objects and number of times they appeared.   

foreach($key in $stats.keys)

{

   $builder = $builder.AppendLine($key + $global:g_CSVDelimiter + $stats[$key])

}

 

$csvFile       = "ObjectsLeaking.CSV"

$csvFileSorted = "SortedObjectsLeaking.CSV"

 

# Send output to the CSV file.

out-file -filepath $csvFile -inputobject "$builder"  

 

# Sort CSV file and select the top 10 items based on occurrences.

import-csv $csvFile | sort-object Occurrences -desc | select-Object -first 20 | export-csv $csvFileSorted -notypeinformation

 

# Creates LogParser file.

[string] $logParser = "logparser.exe `"SELECT ObjectsLeaking, Occurrences INTO Top20ObjectsLeaking.gif FROM " + [system.io.path]::GetFullPath($csvFileSorted) + " ORDER BY Occurrences DESC`" -i:CSV -o:CHART -charttype:ColumnClustered -groupsize:512x480 -chartTitle:`"Top 20 Objects Leaking`" -e:1"

 

$batFile = "Top20ObjectsLeakingChart.bat"

out-File -filepath $batFile -inputobject $logParser -encoding "ASCII"

 

write-Host "Done!" -foreground Green -background Black

 

# Notifies user the script finished the execution.

Send-PowerDbgComment "PowerDbgScriptGCHandleLeaks was executed. See the PowerShell window for more information."

 

$content = import-Csv $csvFileSorted

 

write-Host "======= Top 20 Objects Leaking From " ($output.Count - 1) " Objects Leaking =======`n`n" -foreground Red -background Black

 

# Display the top 20 objects leaking.

import-Csv $csvFileSorted

 

write-Host "`nRun " -foreground Green -background Black -nonewline

write-Host $batFile -foreground Red -background Black -nonewline

write-host " from LogParser folder to see the chart." -foreground Green -background Black