diagnostics icon indicating copy to clipboard operation
diagnostics copied to clipboard

How to diagnose memory allocations on Mono platforms?

Open jonathanpeppers opened this issue 1 year ago • 2 comments

Background and Motivation

I'm looking at a .NET MAUI sample on Android:

  • https://github.com/dotnet/maui/issues/23991

It is loading a periodic table, but running many GCs:

[riodictablemaui] Explicit concurrent copying GC freed 933(127KB) AllocSpace objects, 31(4092KB) LOS objects, 49% free, 4423KB/8846KB, paused 1.328ms,169us total 33.513ms
[riodictablemaui] Explicit concurrent copying GC freed 722(46KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 4581KB/9162KB, paused 1.856ms,170us total 14.835ms
[riodictablemaui] Explicit concurrent copying GC freed 641(43KB) AllocSpace objects, 1(108KB) LOS objects, 49% free, 4525KB/9050KB, paused 1.420ms,176us total 14.112ms
[riodictablemaui] Explicit concurrent copying GC freed 619(41KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 4579KB/9158KB, paused 1.263ms,173us total 13.825ms
[riodictablemaui] Explicit concurrent copying GC freed 483(29KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 4630KB/9260KB, paused 1.379ms,171us total 14.170ms
... repeats many more times

I would like to investigate this sample on the .NET side, and understand who's allocating so much. I'm able to investigate allocations using Android Studio on the JVM side:

image

I tried using dotnet-trace --profile gc-verbose, but it doesn't look like GC-related events work on the Mono runtime.

I was looking here, maybe some GC events work, and there is a way this might work currently?

  • https://github.com/dotnet/runtime/blob/eb9c01f844b15115ba87071ed6952664c3ee4c95/src/coreclr/vm/ClrEtwAll.man#L9457

Proposed Feature

What I would like is some report:

  • Allocations (in bytes) per assembly, namespace, type, etc.
  • Ability to see the stack trace, where the object was allocated

Usage Examples

I think ideally, dotnet-trace --profile gc-verbose would work to align with this existing doc on CoreCLR:

  • https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace

jonathanpeppers avatar Aug 14 '24 13:08 jonathanpeppers

Mono didn't implement all GC events currently emitted by coreclr GC. Mono implemented enough to support legacy Mono profiler events as well as taking gcdumps using dotnet-gcdump tooling. There are some legacy Mono profiler events that can be used to track GC allocations and tie them to callstacks, but it won't work with existing dotnet tooling since its old Mono profiler specific events. Fix for this is to enhance Mono GC to emit enough EventPipe events to gc-verbose or at least find a smaller subset that has enough values.

Tracking memory increases is currently handled using dotnet-gcdump and compare diffs between snapshot locations.

lateralusX avatar Aug 22 '25 08:08 lateralusX

This might be something that is just solved when CoreCLR is finished.

We've been able to get by with taking dotnet-gcdump and diffing them, but you can't see a call stack who allocated. You can see a path to what keeps the object alive, though.

jonathanpeppers avatar Aug 22 '25 13:08 jonathanpeppers