I use the NetBeans profiler (which is actually an embedded VisualVM) to monitor the memory consumption of my Java applications. I use the heap view, the surviving generation view, and memory dumps to track memory leaks.
The heap view shows the total of used memory, but it's a bit chaotic, due to the way the garbage collector manages the memory. The graph is essentially sawtooth-shaped, and thus not particularly readable. Sometimes, I force the GC to happen, so that I can have a more precise value of the real memory consumption.
I was wondering : is there a garbage collector which is more appropriate for memory profiling, and which would yield a heap graph closer to the real memory usage ? Or more generally, what JVM settings (-XX options or other) can I use in order to efficiently track memory leaks ?
What you are seeing in your graph is the real behavior of your applications memory utilization. The repeated sawtooth pattern is likely due to allocations of short lived objects which are being scavenged. If you believe you have a memory leak, take a heap dump snapshot and see what objects are being retained in the heap. You can take a snapshot using JConsole and open the resulting dumpfile using HPjmeter.
I suggest you use the GC you intend to use without the profiler. Using this approach you will get a graph which is more like how the application will behave, though not always as readable.
If you want a graph which is more readable, but not as realistic, you can increase the minimum memory size to say 1 GB. This will result in less GCs and a less spikey graph but may not help you except make the graph prettier.
Related
We operate a Java application that we did not develop.
This application uses quite a lot of memory for certain tasks, depending on the data, that is manipulated, up to 4GB. At other times, very little memory is needed, around 300MB.
Once the JVM grabs hold of a lot of memory, it takes a very long time until the garbage is collected and even longer until memory is returned back to the operating system. That's a problem for us.
What happens is as follows: The JVM needs a lot of memory for a task and grabs 4GB of Ram to create a 4GB Heap. Then, after processing finished, the memory is filled only 30%-50%. It takes a long time for memory consumption to change. When I trigger a GC (via jConsole) the heap shrinks below 500MB. Another triggered GC and the heap shrinks to 200MB. Sometimes memory is returned to the system, often not.
Here is typical screenshot of VisualVM. The Heap is collected (Used heap goes down) but Heap size stays up. Only when I trigger the GC through the "Perform GC"-Button, Heap size is reduced.
How can we tune the GC to collect memory much earlier? Performance and GC-Pause-Times are not much of an issue for us. We would rather have more and earlier GCs to reduce memory in time.
And how can we tweak the JVM to release memory back to the operating system, making the memory used by the JVM smaller?
I do know -XX:MinHeapFreeRatio and -XX:MaxHeapFreeRatio, which helps a bit, but watching the heap with VisualVM shows us, that it's not always obeyed. We set MaxHeapFreeRatio to 40% and see in VisualVM, that the heap is only filled to about 10%.
We can't reduce the maximum memory (-Xmx) since sometimes, for a short period, a lot of memory is acutally needed.
We are not limited to a particular GC. So any GC that solves the problem best can be applied.
We use the Oracle Hotspot JVM 1.8
I'm assuming you use the HotSpot JVM.
Then you can use the JVM-Option -XX:InitiatingHeapOccupancyPercent=n (0<=n<=100) to force the JVM to do garbage collection more often. when you set n to 0, constant GC should take place. But I'm not sure whether this is a good idea regarding your applications response time.
I'm using the VisualVM to profile a javafx 8 application that does some graphing and uses a lot more memory than I would like. It doesn't seem to be leaking, but for some reason my total heap never decreases even though my used heap spikes up and down as I select different files to graph. All the spikes up are when I graph a new file and then drops back down when I exit that screen, but total heap just shoots up and remains constant. Is this normal?
Yes that's normal. The JVM allocates more heap memory from the OS and doesn't give it back but the actual usage may vary, i.e. the currently unused portion of the heap may change.
One reason is that allocating memory from the OS is somewhat costly and the data might actually be fragmented once written. Garbage collection might free chunks of memory and thus the used size gets reduced but the still used chunks might be spread out all over the total heap memory.
I'm not sure how the JVM actually handles that in detail (in fact different JVMs might handle that differently) but you might look up free lists, buddy systems etc. that are used in such situations.
One could argue that the JVM could "defragment" the memory after garbage collection and release excess heap memory afterwards but that would be quite a performance hit, especially if lots of data would have to be moved around in RAM or even virtual/swap memory. As with many computing problems it's a tradeoff between space and cpu usage.
I am monitoring my Java application (written in JDK 1.7) using VisualVM. Following is the graph that shows heap memory usage for the duration that this application ran.
Looking at this graph ones see that there are a lot of spikes in it. These spikes indicate creation of objects by the application. Once the application is done with them it destroys them using gc (implicitly called in this case).
Also , here is a screenshot of memory profiler when the application is still running
To me the up and down nature of the graph indicates efficient usage of java objects. Is this inference right ?
What is the ideal nature of the heap usage graph that one should aim for ?
Are there any other ways that I can improve on the heap memory usage by my application ?
To me the up and down nature of the graph indicates efficient usage of java objects. Is this inference right ?
I would say its the efficient use of the garbage collector. I would suggest creating less object might be more efficient.
What is the ideal nature of the heap usage graph that one should aim for ?
That depends on your application. I tend to aim for one which is almost completely flat.
Are there any other ways that I can improve on the heap memory usage by my application ?
Loads
create less garbage. Use your memory profiler to find out where garbage is being created.
make the heap larger so it doesn't GC as often.
move your retained data off heap (you don't appear to have a lot)
In your case, the best option would be to reduce the amount of garbage you are producing.
As long as the heap size keep almost same over time, you are ok. Used heap should go up and down due to the nature of pause the world gc in Sun JVM. Looks like lots of short lived objects are produced in your app, it may be inefficient, but sometimes you need create them. It's the lifestyle of Java :D
My point is, since there's limited amount of heapsize, does the JVM need to run garbage collection more frequently? and practically, is it a performance killer?
The optimal amount of memory to use might be 2-5x the minimum heap to run the program. How often the GC is run is inversely proportional to the amount of free memory after a GC.
practically, is it a performance killer?
That depends on your application, but I would assume it is.
Given RAM is relative cheap compared to the cost of your time, I tend to make sure I have plenty of RAM. You can buy 16 GB for less than $80.
This kind of depends on the algorithm used for the gc and the jdk you are using. The normal gc is a killer as it stops execution of the other threads. If you are on jdk 1.6 or better you can make this visible using e.g. visualVM.
There are different gc algorithms to overcome this. Here I would send you to the docs as they the differences best
Finding the right balance between the memory requirements of your application and the memory allocation you give it (using Xmx) is a key performance tuning activity.
Yes, you want to make heap big enough so that the JVM does not end up thrashing on constant GC, which can absolutely be a performance killer.
What heap size you need is totally application dependent.
I am trying to detect memeory leak in my java codes with java profilers VisualVM. I want to report the maximum memory usage before and after I fix a memory leak. While running VisualVM or other java profilers, is there anyway to find out the peak of the memeory usage? Thanks!
You can do this with VisualVM. First, install the VisualVM-MBeans plugin, and restart VisualVM. After that on the new MBeans tab choose java.lang.Memory.HeapMemoryUsage. The max value will give you the maximal allocated memory.
Update:
I double-checked it, and HeapMemoryUsage.max isn't the peak heap usage indeed. Fortunately, there are per-generation peak usage statistics in java.lang.MemoryPool.<Generation>.PeakUsage.used. To verify it, I wrote a small program that allocates some memory, and PeakUsage.max for Eden Space plus Old Gen plus Survivor Space gives the desired peak heap usage.
So here's what you can do:
You can use these per-generation statistics. You can also write some small tool that computes and prints the sum of the peak use of each generation for a given process via JMX.
If you only need some approximation, you can check the Monitor tab in VisualVM, the purple area on the Heap chart is Used Heap, so you can get some idea about the peak usage as well.
If you need this to eliminate a memory leak, what you really need is the long-time memory allocation pattern, and again, that is available on the Heap chart in VisualVM. This is a good start.
You can call Runtime.maxMemory() for how much memory the VM had allocated (this usually doesn't shrink). If you do this in a shutdown hook, then the value should be pretty accurate.
Use jmap or -XX:+HeapDumpOnCtrlBreak to accurately measure the memory used in your application at any given time. Both of these mechanisms trigger a GC when the memory snapshot is taken, so its more accurately reflects the contents and size of the heap. You can use jhat to open the heap dump.