Finding memory usage in Java

Below is the script I need to solve. I hit with two solutions.

I need to save a cache of data retrieved from a database that will be displayed in the Swing GUI. Whenever my JVM memory exceeds 70% of the allocated memory, I need to warn the user about excessive use. And as soon as the JVM memory usage exceeds 80%, I have to stop all database queries and clear the existing cache as part of user operations and notify the user. During the cleanup process, I manually process the deletion of some data based on some rules and instructs the JVM for the GC. Whenever GC occurs, if the memory is cleared and reaches 60% of the allocated memory, I need to restart all database processing and return control to the user.

To check the statistics of the JVM memory, I found the following two solutions. It was not possible to decide which one is best and why.

  • Runtime.freeMemory () - A thread is created that runs every 10 seconds and checks for free memory, and if the memory exceeds the specified limits, the necessary pop-ups will be an intimate user and will call methods to stop operations and free memory.

  • MemoryPoolMXBean.getUsage () - Java 5 introduced JMX for taking a snapshot of memory at runtime. In JMX, I cannot use the Threshold notification, since it will only notify when the memory reaches / exceeds the set value. The only way to use it is to poll in MemoryMXBean and check the memory statistics for the period.

In the case of using the survey, it seems to me that both implementations will be the same.

Please offer the advantages of the methods and, if there are any other alternatives / any corrections to the methods used.

+6
java garbage-collection memory-management memory
source share
8 answers

Just a side note: Runtime.freeMemory() does not indicate the amount of memory remaining from the allocation, it is just the amount of free memory within the currently allocated memory (which is initially less than the maximum memory in which the virtual machine is configured) to use), but grows over time .

When starting the virtual machine, the maximum memory ( Runtime.maxMemory() ) simply defines the upper limit of memory that the VM can allocate (configured using the -Xmx VM option). Shared memory ( Runtime.totalMemory() ) is the initial size of memory allocated for the virtual machine process (configurable using the -Xms VM option) and will dynamically grow each time you allocate more than its free part ( Runtime.freeMemory() ) until it reaches maximum memory.

The indicator that interests you is the memory available for further placement:

 long usableFreeMemory= Runtime.getRuntime().maxMemory() -Runtime.getRuntime().totalMemory() +Runtime.getRuntime().freeMemory() 

or

 double usedPercent=(double)(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory())/Runtime.getRuntime().maxMemory() 
+14
source share

The usual way to handle this is to use WeakReference and SoftReference s. You need to use both parameters - a weak link means that you do not hold several copies of things, and soft links mean that the GC will hang on things until it starts to run out of memory.

If you need to perform additional cleanups, you can add links to queues and override queue notification methods to start cleaning. All this is fun, but you need to understand what these classes do.

+7
source share

For the JVM, it’s quite normal to work up to 100% of the memory usage, and 10% after GC, and do it every few seconds.

You will not need to try to manage memory in this way. You cannot tell how much memory is saved until the GC starts up completely.

I suggest you sort out what you are really trying to achieve and look at the problem differently.

+5
source share

The requirements you specify are in clear conflict with how the garbage collection works in the JVM.

due to the behavior of the JVM, it will be very difficult to warn you users correctly. In general, shutting down als databases, cleaning up and starting up again is really not the way to go.

Let the JVM do what it should do, handle all the memory associated with you. Modern generations of JVMs are very good at this and with some granularity of the GC parameters, you will get much cleaner memory processing and then force yourself

Articles like http://www.kodewerk.com/advice_on_jvm_heap_tuning_dont_touch_that_dial.htm mention the pros and cons and offer a good explanation of what VM does for you

+4
source share

I used only the first method for a similar task, and everything was in order.

One thing that you should note for both methods is to implement some kind of debouncing - that is, as soon as you find out that you have gained 70% of the memory, wait a minute (or at any other time when you see fit) ) - GC can start at this time and clear a lot of memory.

If you implement the Runtime.freeMemory () graph on your system, you will see how memory constantly goes up and down, up and down.

+2
source share

VisualVM is slightly better than JConsole because it gives you a nice visual look of the garbage collector.

+1
source share

Take a look at JConsole. It displays the necessary information, so you need to adapt it to your needs (given that you are running Sun Java 6).

It also allows you to separate the observation process from what you want to see.

0
source share

Very late after the original post, I know, but I thought I'd post an example of how I did it. Hope this will be useful to someone (I emphasize this is a proof of a prime example, nothing more ... not particularly elegant :))

Just insert these two functions into the class and it should work.

EDIT: Oh and import java.util.ArrayList; import java.util.List; import java.util.ArrayList; import java.util.List;

 public static int MEM(){ return (int)(Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory() +Runtime.getRuntime().freeMemory())/1024/1024; } public static void main(String[] args) throws InterruptedException { List list = new ArrayList(); //get available memory before filling list int initMem = MEM(); int lowMemWarning = (int) (initMem * 0.2); int highMem = (int) (initMem *0.8); int iteration =0; while(true) { //use up some memory list.add(Math.random()); //report if(++iteration%10000==0) { System.out.printf("Available Memory: %dMb \tListSize: %d\n", MEM(),list.size()); //if low on memory, clear list and await garbage collection before continuing if(MEM()<lowMemWarning) { System.out.printf("Warning! Low memory (%dMb remaining). Clearing list and cleaning up.\n",MEM()); //clear list list = new ArrayList(); //obviously, here is a good place to put your warning logic //ensure garbage collection occurs before continuing to re-add to list, to avoid immediately entering this block again while(MEM()<highMem) { System.out.printf("Awaiting gc...(%dMb remaining)\n",MEM()); //give it a nudge Runtime.getRuntime().gc(); Thread.sleep(250); } System.out.printf("gc successful! Continuing to fill list (%dMb remaining). List size: %d\n",MEM(),list.size()); Thread.sleep(3000); //just to view output } } } } 

EDIT. However, this approach still relies on judicious memory tuning in jvm using -Xmx.

EDIT2: It seems that the gc query string really helps with this, at least on my jvm. YMMV.

0
source share

All Articles