On most platforms, Mono generates code dynamically as your software runs. The Instruments profiler does not have the ability to map a memory address of the generated code back to the name of your function being executed. This makes it pretty hard to find the hot spots in your code, or the bit of code responsible for a memory leak.
To solve this problem, you can use Mono's ahead of time compiler to precompile your code to native code. This will improve startup performance and also give you symbols in stack traces in Instruments.
To do this, run mono with the --aot flag over all of the assemblies that your project uses. This is the script that I ran to precompile all of my system libraries:
cd /mono/lib/mono for i in `find gac -name '*dll'` */mscorlib.dll; do mono --aot $i done
This precompiles all of the assemblies from the Global Assembly Cache (GAC) and also takes care of all of my mscorlib libraries (these are not loaded from the GAC).
Then you need to add your own software:
$ mono --aot bin/Debug/*.{exe,dll}
Now, when you use Instruments, you will get nice symbolic stack traces for your process.
Thanks to Alan McGovern for showing me this trick.