Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions documentation/sos-debugging-extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ importance. Shortcut names for popular functions are listed in parenthesis. Type
DumpHeap (dumpheap) DumpStack (dumpstack)
DumpVC EEStack (eestack)
GCRoot (gcroot) CLRStack (clrstack)
PrintException (pe) GCInfo
EHInfo
ObjSize GCInfo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add (objsize) after ObjSize.

PrintException (pe) EHInfo
bpmd (bpmd)

Examining CLR data structures Diagnostic Utilities
----------------------------- -----------------------------
DumpDomain (dumpdomain) VerifyHeap
EEHeap (eeheap) FindAppDomain
Name2EE (name2ee) DumpLog (dumplog)
DumpMT (dumpmt)
DumpClass (dumpclass)
DumpMD (dumpmd)
EEHeap (eeheap) FindAppDomain
Name2EE (name2ee) GCHandles
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add (gchandles) after GCHandles.

DumpMT (dumpmt) DumpLog (dumplog)
DumpClass (dumpclass) SuppressJitOptimization
DumpMD (dumpmd) ThreadPool (threadpool)
Token2EE
DumpModule (dumpmodule)
DumpAssembly
Expand Down Expand Up @@ -98,6 +98,7 @@ importance. Shortcut names for popular functions are listed in parenthesis. Type
|**EHInfo** [\<*MethodDesc address*>] [\<*Code address*>]|Displays the exception handling blocks in a specified method. This command displays the code addresses and offsets for the clause block (the `try` block) and the handler block (the `catch` block).|
|**FAQ**|Displays frequently asked questions.|
|**FindAppDomain** \<*Object address*>|Determines the application domain of an object at the specified address.|
|**GCHandles** [**-perdomain**]|Displays statistics about garbage collector handles in the process.<br /><br /> The **-perdomain** option arranges the statistics by application domain.<br /><br /> Use the **GCHandles** command to find memory leaks caused by garbage collector handle leaks. For example, a memory leak occurs when code retains a large array because a strong garbage collector handle still points to it, and the handle is discarded without freeing it.|
|**GCInfo** \<*MethodDesc address*>\<*Code address*>|Displays data that indicates when registers or stack locations contain managed objects. If a garbage collection occurs, the collector must know the locations of references to objects so it can update them with new object pointer values.|
|**GCRoot** [**-nostacks**] [**-all**] \<*Object address*>|Displays information about references (or roots) to an object at the specified address.<br /><br /> The **GCRoot** command examines the entire managed heap and the handle table for handles within other objects and handles on the stack. Each stack is then searched for pointers to objects, and the finalizer queue is also searched.<br /><br /> This command does not determine whether a stack root is valid or is discarded. Use the **clrstack** and **U** commands to disassemble the frame that the local or argument value belongs to in order to determine if the stack root is still in use.<br /><br /> The **-nostacks** option restricts the search to garbage collector handles and reachable objects.<br /><br /> The **-all** option forces all roots to be displayed instead of just the unique roots.|
|**GCWhere** *\<object address>*|Displays the location and size in the garbage collection heap of the argument passed in. When the argument lies in the managed heap but is not a valid object address, the size is displayed as 0 (zero).|
Expand All @@ -109,6 +110,7 @@ importance. Shortcut names for popular functions are listed in parenthesis. Type
|**HistRoot** *\<root>*|Displays information related to both promotions and relocations of the specified root.<br /><br /> The root value can be used to track the movement of an object through the garbage collections.|
|**IP2MD** (**ip2md**) \<*Code address*>|Displays the `MethodDesc` structure at the specified address in code that has been JIT-compiled.|
|**Name2EE** (**name2ee**) \<*module name*> \<*type or method name*><br /><br /> -or-<br /><br /> **Name2EE** \<*module name*>**!**\<*type or method name*>|Displays the `MethodTable` structure and `EEClass` structure for the specified type or method in the specified module.<br /><br /> The specified module must be loaded in the process.<br /><br /> To get the proper type name you can browse the module by using the an IL reflection tool like Ildasm or ILSpy. You can also pass `*` as the module name parameter to search all loaded managed modules. The *module name* parameter can also be the debugger's name for a module, such as `mscorlib` or `image00400000`.<br /><br /> This command supports the Windows debugger syntax of <`module`>`!`<`type`>. The type must be fully qualified.|
|**ObjSize** [\<*Object address*>] &#124; [**-aggregate**] [**-stat**]|Displays the size of the specified object. If you do not specify any parameters, the **ObjSize** command displays the size of all objects found on managed threads, displays all garbage collector handles in the process, and totals the size of any objects pointed to by those handles. The **ObjSize** command includes the size of all child objects in addition to the parent.<br /><br /> The **-aggregate** option can be used in conjunction with the **-stat** argument to get a detailed view of the types that are still rooted. By using **!dumpheap -stat** and **!objsize -aggregate -stat**, you can determine which objects are no longer rooted and diagnose various memory issues.|
|**PrintException** [**-nested**] [**-lines**] [\<*Exception object address*>]<br /><br /> -or-<br /><br /> **PE** [**-nested**] [\<*Exception object address*>]|Displays and formats fields of any object derived from the <xref:System.Exception> class at the specified address. If you do not specify an address, the **PrintException** command displays the last exception thrown on the current thread.<br /><br /> The **-nested** option displays details about nested exception objects.<br /><br /> The **-lines** option displays source information, if available.<br /><br /> You can use this command to format and view the `_stackTrace` field, which is a binary array.|
|**SyncBlk** [**-all** &#124; \<*syncblk number*>]|Displays the specified `SyncBlock` structure or all `SyncBlock` structures. If you do not pass any arguments, the **SyncBlk** command displays the `SyncBlock` structure corresponding to objects that are owned by a thread.<br /><br /> A `SyncBlock` structure is a container for extra information that does not need to be created for every object. It can hold COM interop data, hash codes, and locking information for thread-safe operations.|
|**SOSFlush**|Flushes an internal SOS cache.|
Expand Down
2 changes: 1 addition & 1 deletion src/SOS/SOS.Hosting/Commands/SOSCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace SOS.Hosting
[Command(Name = "watsonbuckets", DefaultOptions = "WatsonBuckets", Platform = CommandPlatform.Windows, Help = "Displays the Watson buckets.")]
[Command(Name = "comstate", DefaultOptions = "COMState", Platform = CommandPlatform.Windows, Help = "Lists the COM apartment model for each thread.")]
[Command(Name = "gchandles", DefaultOptions = "GCHandles", Help = "Provides statistics about GCHandles in the process.")]
[Command(Name = "objsize", DefaultOptions = "ObjSize", Platform = CommandPlatform.Windows, Help = "Lists the sizes of the all the objects found on managed threads.")]
[Command(Name = "objsize", DefaultOptions = "ObjSize", Help = "Lists the sizes of the all the objects found on managed threads.")]
[Command(Name = "gchandleleaks", DefaultOptions = "GCHandleLeaks", Platform = CommandPlatform.Windows, Help = "Helps in tracking down GCHandle leaks")]
public class SOSCommand : CommandBase
{
Expand Down
2 changes: 2 additions & 0 deletions src/SOS/Strike/sos_unixexports.src
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ EHInfo
ext
FinalizeQueue
FindAppDomain
GCHandles
GCInfo
GCRoot
Help
Expand All @@ -47,6 +48,7 @@ HistStats
IP2MD
logging
Name2EE
ObjSize
PrintException
PathTo
StopOnCatch
Expand Down
127 changes: 122 additions & 5 deletions src/SOS/Strike/sosdocsunix.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ DumpHeap (dumpheap) EEStack (eestack)
DumpVC ClrStack (clrstack)
FinalizeQueue (finalizequeue) GCInfo
GCRoot (gcroot) EHInfo
PrintException (pe) bpmd (bpmd)
ObjSize bpmd (bpmd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put (objsize) after ObjSize? This indicates that on lldb/dotnet-dump that the lowercase alias is available.

PrintException (pe)

Examining CLR data structures Diagnostic Utilities
----------------------------- -----------------------------
DumpDomain (dumpdomain) VerifyHeap
EEHeap (eeheap) FindAppDomain
Name2EE (name2ee) DumpLog (dumplog)
SyncBlk (syncblk) SuppressJitOptimization
DumpMT (dumpmt) ThreadPool (threadpool)
DumpClass (dumpclass)
Name2EE (name2ee) GCHandles
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add (gchandles) after GCHandles.

SyncBlk (syncblk) DumpLog (dumplog)
DumpMT (dumpmt) SuppressJitOptimization
DumpClass (dumpclass) ThreadPool (threadpool)
DumpMD (dumpmd)
Token2EE
DumpModule (dumpmodule)
Expand Down Expand Up @@ -487,6 +488,44 @@ objects, there is a -nostacks option.
The -all option forces all roots to be displayed instead of just the unique roots.
\\

COMMAND: objsize.
ObjSize [<Object address>]

With no parameters, ObjSize lists the size of all objects found on managed
threads. It also enumerates all GCHandles in the process, and totals the size
of any objects pointed to by those handles. In calculating object size,
ObjSize includes the size of all child objects in addition to the parent.

For example, DumpObj lists a size of 20 bytes for this Customer object:

(lldb) dumpobj a79d40
Name: Customer
MethodTable: 009038ec
EEClass: 03ee1b84
Size: 20(0x14) bytes
(C:\pub\unittest.exe)
Fields:
MT Field Offset Type Attr Value Name
009038ec 4000008 4 CLASS instance 00a79ce4 name
009038ec 4000009 8 CLASS instance 00a79d2c bank
009038ec 400000a c System.Boolean instance 1 valid

but ObjSize lists 152 bytes:

(lldb) ObjSize a79d40
sizeof(00a79d40) = 152 ( 0x98) bytes (Customer)

This is because a Customer points to a Bank, has a name, and the Bank points to
an Address string. You can use ObjSize to identify any particularly large
objects, such as a managed cache in a web server.

While running ObjSize with no arguments may point to specific roots that hold
onto large amounts of memory it does not provide information regarding the
amount of managed memory that is still alive. This is due to the fact that a
number of roots can share a common subgraph, and that part will be reported in
the size of all the roots that reference the subgraph.
\\

COMMAND: pe.
COMMAND: printexception.
PrintException [-nested] [-lines] [-ccw] [<Exception object address>] [<CCW pointer>]
Expand Down Expand Up @@ -1763,6 +1802,84 @@ Objects with Finalizers are the easiest case, as the CLR needs to be able to
call those when an AppDomain shuts down.
\\

COMMAND: gchandles.
GCHandles [-type handletype] [-stat] [-perdomain]

GCHandles provides statistics about GCHandles in the process.

Paremeters:
stat - Only display the statistics and not the list of handles and
what they point to.
perdomain - Break down the statistics by the app domain in which
the handles reside.
type - A type of handle to filter it by. The handle types are:
Pinned
RefCounted
WeakShort
WeakLong
Strong
Variable
AsyncPinned
SizedRef

Sometimes the source of a memory leak is a GCHandle leak. For example, code
might keep a 50 Megabyte array alive because a strong GCHandle points to it,
and the handle was discarded without freeing it.

The most common handles are "Strong Handles," which keep the object they point
to alive until the handle is explicitly freed. "Pinned Handles" are used to
prevent the garbage collector from moving an object during collection. These
should be used sparingly, and for short periods of time. If you don't follow
that precept, the gc heap can become very fragmented.

Here is sample output from a very simple program. Note that the "RefCount"
field only applies to RefCount Handles, and this field will contain the
reference count:

0:000> !GCHandles
Handle Type Object Size RefCount Type
001611c0 Strong 01d00b58 84 System.IndexOutOfRangeException
001611c4 Strong 01d00b58 84 System.IndexOutOfRangeException
001611c8 Strong 01d1b48c 40 System.Diagnostics.LogSwitch
001611d0 Strong 01cfd2c0 36 System.Security.PermissionSet
001611d4 Strong 01cf7484 56 System.Object[]
001611d8 Strong 01cf1238 32 System.SharedStatics
001611dc Strong 01cf11c8 84 System.Threading.ThreadAbortException
001611e0 Strong 01cf1174 84 System.Threading.ThreadAbortException
001611e4 Strong 01cf1120 84 System.ExecutionEngineException
001611e8 Strong 01cf10cc 84 System.StackOverflowException
001611ec Strong 01cf1078 84 System.OutOfMemoryException
001611f0 Strong 01cf1024 84 System.Exception
001611f8 Strong 01cf2068 48 System.Threading.Thread
001611fc Strong 01cf1328 112 System.AppDomain
001613ec Pinned 02cf3268 8176 System.Object[]
001613f0 Pinned 02cf2258 4096 System.Object[]
001613f4 Pinned 02cf2038 528 System.Object[]
001613f8 Pinned 01cf121c 12 System.Object
001613fc Pinned 02cf1010 4116 System.Object[]

Statistics:
MT Count TotalSize Class Name
563266dc 1 12 System.Object
56329708 1 32 System.SharedStatics
5632bc38 1 36 System.Security.PermissionSet
5635f934 1 40 System.Diagnostics.LogSwitch
5632759c 1 48 System.Threading.Thread
5632735c 1 84 System.ExecutionEngineException
56327304 1 84 System.StackOverflowException
563272ac 1 84 System.OutOfMemoryException
563270c4 1 84 System.Exception
56328914 1 112 System.AppDomain
56335f78 2 168 System.IndexOutOfRangeException
563273b4 2 168 System.Threading.ThreadAbortException
563208d0 5 16972 System.Object[]
Total 19 objects

Handles:
Strong Handles: 14
Pinned Handles: 5
\\

COMMAND: histinit.
HistInit

Expand Down
12 changes: 4 additions & 8 deletions src/SOS/Strike/strike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11237,6 +11237,8 @@ DECLARE_API(FindRoots)
#endif
}

#endif // FEATURE_PAL

class GCHandleStatsForDomains
{
public:
Expand Down Expand Up @@ -11379,7 +11381,7 @@ class GCHandlesImpl
if (!GetCMDOption(args,option,ARRAY_SIZE(option),NULL,0,NULL))
sos::Throw<sos::Exception>("Failed to parse command line arguments.");

if (type != NULL)
if (type != NULL) {
if (_stricmp(type, "Pinned") == 0)
mType = HNDTYPE_PINNED;
else if (_stricmp(type, "RefCounted") == 0)
Expand All @@ -11402,6 +11404,7 @@ class GCHandlesImpl
mType = HNDTYPE_WEAK_WINRT;
else
sos::Throw<sos::Exception>("Unknown handle type '%s'.", type.GetPtr());
}
}

void Run()
Expand Down Expand Up @@ -11985,10 +11988,8 @@ DECLARE_API(StopOnException)
\**********************************************************************/
DECLARE_API(ObjSize)
{
#ifndef FEATURE_PAL
INIT_API();
MINIDUMP_NOT_SUPPORTED();
ONLY_SUPPORTED_ON_WINDOWS_TARGET();

BOOL dml = FALSE;
StringHolder str_Object;
Expand Down Expand Up @@ -12031,10 +12032,6 @@ DECLARE_API(ObjSize)
ExtOut("sizeof(%p) = %d (0x%x) bytes (%S)\n", SOS_PTR(obj), size, size, methodTable.GetName());
}
return Status;
#else
return E_NOTIMPL;
#endif

}

#ifndef FEATURE_PAL
Expand Down Expand Up @@ -12237,7 +12234,6 @@ DECLARE_API(GCHandleLeaks)
}
#endif // FEATURE_PAL

#endif // FEATURE_PAL

class ClrStackImplWithICorDebug
{
Expand Down
2 changes: 2 additions & 0 deletions src/SOS/lldbplugin/soscommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ sosCommandInitialize(lldb::SBDebugger debugger)
g_services->AddCommand("eestack", new sosCommand("EEStack"), "Runs dumpstack on all threads in the process.");
g_services->AddCommand("eeversion", new sosCommand("EEVersion"), "Displays information about the runtime version.");
g_services->AddCommand("finalizequeue", new sosCommand("FinalizeQueue"), "Displays all objects registered for finalization.");
g_services->AddCommand("gchandles", new sosCommand("GCHandles"), "Displays statistics about garbage collector handles in the process.");
g_services->AddCommand("gcroot", new sosCommand("GCRoot"), "Displays info about references (or roots) to an object at the specified address.");
g_services->AddCommand("gcwhere", new sosCommand("GCWhere"), "Displays the location in the GC heap of the argument passed in.");
g_services->AddCommand("ip2md", new sosCommand("IP2MD"), "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.");
Expand All @@ -190,6 +191,7 @@ sosCommandInitialize(lldb::SBDebugger debugger)
g_services->AddCommand("histobj", new sosCommand("HistObj"), "Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to the address passed in as an argument.");
g_services->AddCommand("histobjfind", new sosCommand("HistObjFind"), "Displays all the log entries that reference an object at the specified address.");
g_services->AddCommand("histroot", new sosCommand("HistRoot"), "Displays information related to both promotions and relocations of the specified root.");
g_services->AddCommand("objsize", new sosCommand("ObjSize"), "Displays the size of the specified object.");
g_services->AddCommand("setclrpath", new sosCommand("SetClrPath"), "Set the path to load the runtime DAC/DBI files.");
g_services->AddCommand("setsymbolserver", new sosCommand("SetSymbolServer"), "Enables the symbol server support ");
g_services->AddCommand("sympath", new sosCommand("SetSymbolServer", "-sympath"), "Add server, cache and directory paths in the Windows symbol path format.");
Expand Down