6

I improved my code to get a better result from the garbage collector.

Now when i call System.gc() it does free all memory. But when I watch the memory usage without calling System.gc() the application does reserve and use more and more memory.

Does it mean my improvements are working and I got all my references right and I can ignore how the JVM does free memory by itself. Or are there another problems in my code that are the reasons why the JVM does reserve more memory without running the garbage collector.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
Dennis
  • 143
  • 5
  • 17

4 Answers4

5

Depends which GC your JVM is using. If it is JDK9 then its probably G1 which is 'greedy' when it comes to memory consumption, so depending on the way in which you are checking memory utilized, it can appear as if it is taking up a lot of memory (where as this is reserving it and using/freeing dynamically/on demand.

You can use

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

to check memory consumption.

And as for GC and memory consumption analysis check out following: High memory usage issues with G1 Garbage collector + https://www.javacodegeeks.com/2017/11/minimize-java-memory-usage-right-garbage-collector.html

ejaksla
  • 128
  • 1
  • 7
3

Unused memory is wasted memory.

Why do you want to explicitly call System.gc(). IMHO, you should never call it and leave it up to the JVM to decide when to run GC. (JVM can make better decisions than you if you are a novice. Call System.gc() only when you really know what you are doing.) It's generally a bad practice to call System.gc().

System.gc() is just a request/hint to the JVM to run GC. It in no way means that for sure GC will run.

You can have memory leaks in Java, but that's for sure not the thing to look at in your case because as you mentioned when you invoke System.gc() you can see some memory getting freed up. (So it is not the case that you are still holding the reference of unused objects which can prevent GC from cleaning up those objects.)

Why do you think it's a problem with your code? It can be the case that no further memory is required or if memory is required, you already have plenty amount of it (and speaking in layman terms, GC don't frees up memory as there is still a lot for the program to run - so why should GC bother clearing the memory?).

Lavish Kothari
  • 2,211
  • 21
  • 29
  • Thanks for your answer. However, I dont want to use System.gc(). I used it only as a tool to see if the memory will be get released at all. There was a problem with my code but I resolved it now. But i was wondering why the JVM does not free the memory by itself or why it does take so long to release it. – Dennis Jan 19 '19 at 14:29
  • Garbage collection spends compute time to gain useable space. It's far from clear that it's in the interest of "the average program" to want that particular tradeoff. –  Jan 19 '19 at 18:04
  • 1
    @Dennis the JVM will rarely “release” memory. Most of the time, garbage collection will identify unused memory, to the only effect that your monitoring program will show it to you as unused. Modern operating systems don’t rely on releasing memory either. The memory is virtualized and if another program needs physical memory, it can get it whether the memory has been released or not. So this answer nailed it, “unused memory is wasted memory” and neither, the JVM nor the OS will spend resources on just presenting you a larger number of “free memory”. That’s just a number, not a meaningful thing. – Holger Jan 21 '19 at 10:29
1

There is no way to force JVM to free up the memory, System.gc() is just a hint. It's up to GC to manage the memory (do note there are various types of memory e.g. heap, meta space, off-heap). Each GC algorithm has multiple configuration parameters that you can tweak but neither will give you an option to free up the memory on demand.

JVM reserves memory on startup and requests additional memory from the OS until it reaches whatever limits are configured. It does it in chunk increments, requesting MBs or more memory at a time, because requesting memory from the OS byte by byte would be very inefficient.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
  • I know that it is just a hint. But my Question was when System.gc() does free memory does it mean i got all my references right? Because the jvm does not really free the memory by itself. – Dennis Jan 19 '19 at 14:06
  • If you are asking when memory will be returned to OS see, https://stackoverflow.com/a/324505/1602555 – Karol Dowbecki Jan 19 '19 at 14:08
1

There is of course a possibility that you have a memory leak, meaning that your program keeps allocating memory without ever freeing it. (For example, in an ever-growing list or map.) You will need a memory profiler in order to make sure you are not suffering from such a situation.

Other than that, I would not worry if the virtual machine appears to keep allocating memory without freeing it. That's how modern VMs work, especially in "client" mode: for as long as there is plenty of free memory, they will not waste time with garbage collection. If the limit of memory is approached, that's when the garbage collector will kick-in. (The "client" vs. "server" mode is a JVM argument, you can experiment with it if you want, more info here: Real differences between "java -server" and "java -client"?)

Other than that, what you can do is:

a) make sure that your mechanism of performing a full GC is actually performing a full GC. The best mechanism that I know of (which is not guaranteed to work, but it seems to work as far as I can tell) is to allocate an object referenced only via a soft reference, and then keep calling GC until the soft reference becomes null.

b) on a debug run, (say, if assertions are enabled,) keep triggering a full GC on a separate thread every few seconds. Then, if you look at the memory consumed by the VM, it should remain roughly constant. If not, you have a memory leak.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142