Here is the kind of data a profiler can show for memory usage:
Number of object allocations for a specific type.
Places where the object allocations are taking place.
Methods involved in allocation of instances of this class.
Loitering objects: objects that are allocated, not used, and not garbage
collected. These keep increasing the size of the JVM heap and represent memory
leaks, which can cause an out-of-memory error or excessive overhead on the
garbage collector.
Excessive allocation of temporary objects that increase the work of the
garbage collector and thus reduce the performance of the application.
Failure to release instances added to a collection and not removed (this is
a special case of loitering objects).
Tracking CPU usage
Profilers also keep track of how much time the CPU spends in various parts of your code. They can tell you:
The number of times a method was invoked.
The percentage of CPU time utilized by each method. If this method calls
other methods, the profiler can tell you the amount of time spent in these other
methods.
Total absolute time spent by each method, including the time it waits for
I/O, locks, etc. This time depends on the available resources of the
system.
This way you can decide which sections of your code need optimizing.