4

I have an application doing a lot of string manipulation, and I noticed that the jvm memory usage is very high while I'm not even storing anything in memory.

I made a sample application to demonstrate the issue : I have a simple JFrame with one button

private void buttonDoWorkActionPerformed(java.awt.event.ActionEvent evt) {
    String randomString = "abc test garbagecollector";

    ArrayList<String> results;

    for(int i=0; i<100000; i++)
        results = doNothing(randomString.split(" "));

    results = null;//No effect
    System.gc();//No effect
}

private static ArrayList<String> doNothing(String[] words) {
    ArrayList<String> results = new ArrayList<String>();

    for (String word : words)
        results.add(word);

    return results;
}

If you run this sample the JVM takes about 50Mo in the memory, and once you hit the button it will raise to 150Mo and will never go down. EDIT : I am refering to the "java.exe" process in the windows task manager.

Obviously I'm doing a lot of temporary string copies, but I excpect them to be freed by the carbage collector once I lose the references.

EDIT: Maybe not related but I tryed with java 1.6 both 32 and 64 bits versions.

2 Answers 2

5

You need to clarify what you mean by it as there are many levels you might be seeing here. Some will decrease on a GC, some will not.

If you are looking at memory usage after a GC, you should see not increase, and if you are seeing an increase in something else it's likely to be the maximum memory or some other number.

public static long memoryUsed() {
    return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}

public static void main(String... args) {
    String randomString = "abc test garbagecollector";

    System.gc();
    System.out.printf("Memory used before test started %.1f MB%n", memoryUsed() / 1e6);
    for (int t = 0; t < 5; t++) {
        List<String> results = new ArrayList<String>();

        for (int i = 0; i < 100000; i++) {
            for (String word : randomString.split(" "))
                results.add(word);
        }
        long beforeGC = memoryUsed();
        results = null;
        System.gc();
        System.out.printf("%d: before GC %.1f MB used, after GC %.1f MB used%n",
                t, beforeGC / 1e6, memoryUsed() / 1e6);
    }
}

prints

Memory used before test started 5.7 MB
0: before GC 61.8 MB used, after GC 5.8 MB used
1: before GC 44.3 MB used, after GC 5.8 MB used
2: before GC 44.3 MB used, after GC 5.8 MB used
3: before GC 44.3 MB used, after GC 5.8 MB used
4: before GC 44.3 MB used, after GC 5.8 MB used
Sign up to request clarification or add additional context in comments.

5 Comments

I am simple looking at the "java.exe" process in the windows task manager
Java allocates the maximum heap size on start up, this uses virtual memory, not physical memory.
There is something I don't understand here. Whenever it is physical or virtual, java.exe still occupies memory I can't use for another application.
Only your physical memory is limited, your virtual memory is limited to about 256 TB on most modern processors.
But it still doesn't solve the issue : when java.exe exceeds the amount of free memory, I get an out of memory exception. Why would this happen if this is the virtual memory, which is "unlimited".
0

The Strings are probably being interned, this is an issue w/ Java and Strings related to some of the VM design decisions. You can probably try getting VisualVM or some other framework, connect to the JVM you're running and see the objects, and/or do a heap dump and look at the results.

1 Comment

That's not actually an issue, however. Interned strings can also be GC'd once no references to them remain.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.