views:

1013

answers:

2

I have an applet which needs more or less memory depending on how many data the client has.

We usually recommend to use Java 1.6 latest version, but we actually support Java 1.5+ so we have a protection in the applet which shows a dialog box with a warning about "not enough memory" and instructions where to go to increase the memory.

However, I was really surprised to see that -Xmx works differently in applets and standalone processes and I cannot actually determine if the applet has enough memory.

Here is how it is done:

  • the applet receives the following arguments :
    • param name="java_arguments" value="-Xmx153m" (of course this works in Java 1.6 update 10, otherwise it will get 64M in Java 1.5 and Java 1.6 prior update 10)
    • param name="required.memory" value="153"
  • at runtime, we compare required.memory with Runtime.getRuntime().maxMemory()
  • with a limit of 153M in an applet we get 143589376 but in a standalone application we get 155516928
  • 153 * 1000 * 1000 = 153000000 (I'm not using 1024 for 1K, just in case ) which is definitely more than 143589376.

If I'm using a factor of 0.9 to avoid any approximations in JVM seems to work well, but is this the right value - 0.9? How do they calculate this limit and why is it different in standalone applications and applets?

+1  A: 

Time for a spiel on Java memory.

First, running out of memory in Java (ie. actually getting an OutOfMemoryError) is influenced by the peculiarities of the GC that's running.

Contrary to what the name implies, you can get an OutOfMemoryError without actually running out of memory; its also thrown when the runtime decides its spending an inordiate amount of time GC'ing (source, its buried in there).

Additionally, you can get an OutOfMemoryError by running out of specific kinds of memory. Remember that the Java GC is a generational collector, and if you happen to exhaust one of the generations (I want to say the "tenured" one, but I could be wrong) you're also effectively out of memory. This means you can have heap space left from the OS view, but be unable to allocate anything on the Java heap.

Finally, there's some actual overhead associated with the GC that could be eating up some heap space.


What's more likely to be happening in your case, is some variant on the following: your code runs in both a standalone and an applet context, each context has a different security manager and a different startup behavior; this implies that a different set of classes (which get knocked into the permanent generation) are involved, with different dependencies. I'd guess that the applet "stack" is thicker given the more strigent constraints on their behaviors, and that probably accounts for most of the difference in maxMemory().

In short, the difference in available memory is probably due to some change in memory reserved by the Java runtime for its own operation. This could be GC related, security policy related, or just the different classes loaded for the Applet environment vs. the standalone one. Runtime.maxMemory() may also take any of the above "out of memory" conditions into account when determining what to return. Accordingly the 0.9 value is probably an implementation side-effect, one which may change in the future.

Kevin Montrose
A: 

Kevin, indeed it makes sense to be a difference between how an applet runs compared with a desktop application, but what struck me is that there is a big difference in maximum(bigger that I thought) memory available between an applet and a desktop application, which is ~8%.If it is as you said "applet "stack" is thicker given the more strigent constraints on their behaviors" I was expecting that the applet will get a bigger maximum memory and not the stand-alone version.

I took some measurements between the applet and the application. Both received the same parameters(-Xmx128M), both are running with the same JVM - Java HotSpot(TM) 64-Bit Server VM version 11.3-b02(first time I thought the applet was running with client JVM and desktop was running with server JVM, but it seems both are with server JVM)

Of course the JVMs received in reality different parameters, but nothing major(I think):

  • applet : -D__jvm_launched=426431678538 -Xbootclasspath/a:/usr/jvm/64/jdk1.6.0_13/jre/lib/deploy.jar:/usr/jvm/64/jdk1.6.0_13/jre/lib/javaws.jar:/usr/jvm/64/jdk1.6.0_13/jre/lib/plugin.jar -Xmx128m
  • standalone : -Xrunjdwp:transport=dt_socket,address=127.0.0.1:54876,suspend=y,server=n -Xmx128M -Dfile.encoding=UTF-8

Applet : max. memory = 119.314K

  • Heap
    • PS Eden Space : 14,592K
    • PS survivor Space : 14.528K
    • PS Old Gen : 87.424K
      • Total : 116.544K
  • Non-Heap
    • Mem Pool Code Cache : 49.152K
    • Mem Pool PS Perm Gen : 86.016K
      • Total : 135.168K

Desktop : max. memory = 129.302K

  • Heap
    • PS Eden Space : 8.704K
    • PS survivor Space : 3.008K
    • PS Old Gen : 116.544K
      • Total : 126.272K
  • Non-Heap
    • Mem Pool Code Cache : 49.152K
    • Mem Pool PS Perm Gen : 65.536K
      • Total : 135.168K

The big differences between those two JVMs

  • PS Perm Gen, the applet got a bigger chunk - which makes sense since the applet will load probably additional classes compared with the standalone version(but even in this case "Old Gen" is much smaller, which is odd because usually all those additional classes will eventually get in the "Old Gen")
  • Heap memory, totally different ratio between Eden/Survivor/Old Gen. Applet's Old Gen is 75% of the standalone's Old Gen, it's a big difference I would say, I'm kind if expecting (olmost) the same memory model since there shouldn't be any difference when I'm running the application as an applet or as a desktop application.

Now I'm even more confused, not only that I don't know how to calculate the max.memory ratio(indeed 0.9 could not be valid with future JVM versions) but my application could get out of memory when runs as an applet. I would need to increase maximum memory with ~10-15% when it runs as an applet just to be safe.

I'm still not convinced why such a different heap ratio(on the same machine) and a smaller heap(especially considering that an applet needs additional classes).

Any reasons why? I'm curios now, this went beyond my need to check if the applet has the maximum amount of memory that I think it should.

adrian.tarau