• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Problem of freeMemory()?

 
Ranch Hand
Posts: 30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

I am trying to use the freeMemory() of Runtime object to determine the available memory in JVM, so I wrote a simple program to allocate some memory, then free them and call GC to notify system to collect them. Ideally, most allocated memory should be collected by GC. However, every time there are always about half of the memory uncollected, and I don't know if it is the problem of freeMemory() or the GC process! Could someone please take a look at the program below and tell me why the result?

Thanks a lot for your help!

I was using Eclipse to run the program and the result was like:

Space used:6091568
Uncovered space:3033752

[ added code tags - Jim ]
[ January 18, 2007: Message edited by: Jim Yingst ]
 
Ranch Hand
Posts: 177
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There is no guarantee for GC to empty memory immediatly. I think this could be the reason.
JVM runs garbage collector. You can tell JVM to run GC but there is no gurantee if JVM does it or not.
 
Ranch Hand
Posts: 1970
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As previous poster says, you cannot force Java to do a full GC, so results of freeMemory() are not necessarily what you want.

Perhaps you should take a step back and tell us what you really want to achieve? That is, what is the purpose for which you think you need to know the exact free memory?

If it's just for interest, then I'm afraid the answer is that you cannot do what you are trying to do.

If it's to control some aspect of your application's behaviour, then there may be other ways to achieve what you want. For instance, you can use SoftReference to create caches that automatically get flushed when the system is short of memory. Or you can use JVM parameters like -Xmx, -Xms, -XXminHeapFreeRatio and -XXmaxHeapFreeRatio to get the JVM to adapt the heap size automatically to your application's requirements.

Basically, the JVM is in charge of memory allocation and GC. Attempts by programmers to seize control of it usually fail dismally. Instead, you should work with the hooks like the ones mentioned above.
 
James Zhang
Ranch Hand
Posts: 30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for your replies, guys! The reason I am doing the test is for my current project, which processes a large amount of data in memory and always ends up with OutOfMemory exception. One scenario is that I have a list of 830000 objects and need to generate a result string from those objects. One approach I was trying to avoid the memory problem is to free the previous processed objects before doing further processing, but it didn't work. That is the reason why I played with the freeMemory() method to see how GC works for my JVM. I have set the parameter as -Xmx2G (my machine has 3G physical memory) but the problem is still there.

Back to the original program, I believe GC has actually started when the main thread is sleeping (If the statement System.gc() is commented out, you will see that no memory has been collected at all in result). It looks to me that one round of GC does not finish all the work, as only half of the allocated memory is collected. Does anybody know how to make GC collect more memory?

Thanks again for your time!

--James
 
James Zhang
Ranch Hand
Posts: 30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
By the way, I also tried using SoftReference and WeakReference in the array list. The result is a little better than to add string directly to the list, but still there are about 1/3 of the allocated memory uncollected.

--James
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by James Zhang:
Does anybody know how to make GC collect more memory?



When you get an OutOfMemoryError, the GC already is guaranteed to have tried everything in his power to collect memory.

The next thing to do is using a profiler to find out which objects are taking up the memory, and what holds them from being garbage collected.
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
James: Using freeMemory() as you have above can be very misleading. The problem is that it only tells you the difference between the heap memory used and the heap memory currently allocated. Both these quantities can change - as you use more memory, the JVM can allocate more memory to the heap (up to whatever your -Xmx setting is). It would be more useful for you to measure heap usage like this:


[James]: It looks to me that one round of GC does not finish all the work, as only half of the allocated memory is collected. Does anybody know how to make GC collect more memory?

Although your method for measuring memory usage is unreliable, it is true that System.gc() frequently does not do as much work as it could do when you call it. One simple workaround is to simply call it multiple times. In testing this in the past, I've sometimes seen it take at least four consecutive calls before the memory usage stops changing. For memory testing, typically call it 10 times in a row to be safe:

It should be noted that this is still not guaranteed to free all available memory. Fundamentally you never will get a guarantee of that. But this works well enough, if you don't mind the fact that it's horribly, horribly inefficient and should never ever be used in production code. Generally, modern GC works much better if you don't ever call System.gc() yourself. It's been optimized to run on its own, and if you interrupt its routine with System.gc() you usually screw up its efficiency considerably. So this is fine for testing purposes (as long as you're not testing performance), but a bad idea otherwise.

I fully agree with all of Ilja's last post. Rather than studying how well System.gc() does or does not work, focus on figuring out what's in memory when the OutOfMemoryError is thrown. One part of this is: when is the OOME thrown? If you're adding a bunch of data to a List, and the OOME happens before you've had a chance to clear the list at the end, then the problem is probably just that you're putting too much data in the List. Do you really need to have one huge List like that, or can you modify the processing to eliminate the List and just process one item at a time (allowing each already-processed item to be CG-ed when convenient)?

Also, have you tried simply increasing the maximum memory used by your JVM, using the -Xmx switch? See the documentation for java options for details.
[ January 18, 2007: Message edited by: Jim Yingst ]
 
James Zhang
Ranch Hand
Posts: 30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for your valuable comments, Jim and Ilja! I I really appreciate all the helps! We have already used -Xmx2G when starting JVM but seems not helping too much. As your guys pointed out, it is not a good idea to run GC in the codes. My program is just a testing for the GC functionality because I was suspecting that the GC process was not started in our application. Probably a better way is to use tools like JProbe to analyze the memory usage for the application, which is what I am trying to do next.

Again thanks guys!

--James
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Jim Yingst:

It should be noted that this is still not guaranteed to free all available memory. Fundamentally you never will get a guarantee of that.



Just to make this totally clear: there is one important exception to this rule. It *is* guaranteed that all available memory is freed before an OutOfMemoryError is thrown.
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, something like that. Skipping past a semantic discussion of what exactly the specs say (scattered in a number of different places) in practice it seems that the actual behavior is: an OOME will not be thrown unless sufficient memory could not be freed. In some cases the JVM can determine up front that a request would require more memory than it could possibly allocate - e.g. an array that requires more memory than the JVM could possibly have. In such a situation, it may not bother actually freeing up other memory first; it can simply throw OOME right away.

Anyway, it does seem that OOME is not thrown if there is any possible way that sufficient memory could have been allocated. So calling System.gc() still offers nothing that you wouldn't get by default, in terms of freeing up memory when you need it.
 
Peter Chase
Ranch Hand
Posts: 1970
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Agreed. If the problem is that you are getting OutOfMemoryError, then GC is 100% NOT the cause of the problem. Java GC does work and you NEVER need to invoke it explicitly to prevent OutOfMemoryError.

You either have a memory leak in your program or you need more heap. If, as you say, your max heap is already 2GB, then you either have an incredibly memory-intensive application needing specialised (64-bit) hardware, or (more likely) you have a leak.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Jim Yingst:
Well, something like that.



Good point, thanks for the clarification!
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic