Finding Memory Usage in Java

2019-03-20 13:40发布

Following is the scenario i need to solve. I have struck with two solutions.

I need to maintain a cache of data fetched from database to be shown on a Swing GUI. Whenever my JVM memory exceeds 70% of its allocated memory, i need to warn user regarding excessive usage. And once JVM memory usage exceeds 80%, then i have to halt all the database querying and clean up the existing cache fetched as part of the user operations and notifying the user. During cleanup process, i will manually handle deleting some data based up on some rules and instructs JVM for a GC. Whenever GC occurs, if memory cleans up and reaches 60% of the allocated memory, I need to restart all the Database handling and giving back control to the user.

For checking JVM memory statistics i found following two solutions. Could not able to decide which is best way and why.

  1. Runtime.freeMemory() - Thread created to run every 10 seconds and check for the free memory and if memory exceeds the limits mentioned, necessary popups will intimate user and will call the methods to halt the operations and freeing up the memory.

  2. MemoryPoolMXBean.getUsage() - Java 5 has introduced JMX to get the snapshot of the memory at runtime. In, JMX i cannot use Threshold notification since it will only notify when memory reaches/exceeds the given threshhold. Only way to use is Polling in MemoryMXBean and check the memory statistics over a period.

In case of using polling, it seems for me both the implementations are going to be same.

Please suggest the advantages of the methods and if there are any other alternatives/any corrections to the methods using.

8条回答
孤傲高冷的网名
2楼-- · 2019-03-20 14:16

Look into JConsole. It graphs the information you need so it is a matter of adapting this to your needs (given that you run on a Sun Java 6).

This also allows you to detach the surveiling process from what you want to look at.

查看更多
放荡不羁爱自由
3楼-- · 2019-03-20 14:20

Very late after the original post, I know, but I thought I'd post an example of how I've done it. Hopefully it'll be of some use to someone (I stress, it's a proof of principal example, nothing else... not particularly elegant either :) )

Just stick these two functions in a class, and it should work.

EDIT: Oh, andimport 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: This approach still relies on sensible setting of memory in the jvm using -Xmx, however.

EDIT2: It seems that the gc request line really does help things along, at least on my jvm. ymmv.

查看更多
登录 后发表回答