views:

10991

answers:

6

I have a problem with a java application running under linux.

When I launch the application, using the default maximum heap size (64mb), I see using the tops application that 240 MB of virtual Memory are allocated to the application. This creates some issues with some other software on the computer, which is relatively resource-limited.

The reserved virtual memory will not be used anyway, as far as I understand, because once we reach the heap limit an OutOfMemoryError is thrown. I ran the same application under windows and I see that the Virtual Memory size and the Heap size are similar.

Is there anyway that I can configure the Virtual Memory in use for a Java process under Linux?

EDIT: The problem is not the Heap. The problem is that if I set a Heap of 128M, for example, still linux allocates 210 MB of Virtual Memory, which is not needed, ever.

EDIT 2: Using ulimit -v allows limiting the amount of virtual memory. If the size set is below 204 MB, then the application won't run even though it doesn't need 204MB, only 64MB. So I want to understand why java requires so much virtual memory. Can this be changed?

EDIT 3: There are several other applications running in the system, which is embedded. And the system does have a virtual memory limit. (from comments, important detail)

A: 

No, you can't configure memory amount needed by VM. However, note that this is virtual memory, not resident, so it just stays there without harm if not actually used.

Alernatively, you can try some other JVM then Sun one, with smaller memory footprint, but I can't advise here.

Dev er dev
+1  A: 

Sun's java 1.4 has the following arguments to control memory size:

-Xmsn Specify the initial size, in bytes, of the memory allocation pool. This value must be a multiple of 1024 greater than 1MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is 2MB. Examples:

           -Xms6291456
           -Xms6144k
           -Xms6m

-Xmxn Specify the maximum size, in bytes, of the memory allocation pool. This value must a multiple of 1024 greater than 2MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is 64MB. Examples:

           -Xmx83886080
           -Xmx81920k
           -Xmx80m

http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/java.html

Java 5 and 6 have some more. See http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

Paul Tomblin
The problem I have is not with the Heap Size, but with the amount of Virtual Memory that is assigned by Linux
Mario Ortegón
You really don't understand virtual memory. Read kdgregory's explanation. Reducing the heap size, "New size", and the other configurable parameters will reduce the amount of REAL memory the jvm takes.
Paul Tomblin
@Paul: He may have a legitimate problem. Some applications (like one I wrote) mmap a 1 GB file and some systems only have 2 GB of virtual memory, some of which gets filled with shared libraries. And if this is the problem he should definitely disable DSO randomization. There is an option in /proc.
Zan Lynx
+1  A: 

Just a thought, but you may check the influence of a ulimit -v option.

That is not an actual solution since it would limit address space available for all process, but that would allow you to check the behavior of your application with a limited virtual memory.

VonC
That is exactly what my problem is. My Heap is set to 64M, but linux reserves 204MB. If I set the ulimit below 204, the application doesn't run at all.
Mario Ortegón
Interesting: setting the ulimit might have unintended side-effect for other processes, explaining why the application is not able to run.
VonC
The problem seems to be that Java requires to reserve this bigger amount of Virtual memory even though that it won't use it. In windows the virtual memory used and the Xmx setting are rather closer.
Mario Ortegón
Did you try it with a JRockit JVM ?
VonC
Since the memory allocation of the JVM is the sum of the Heap Allocation and of the Perm Size (the first can be fixed using the -Xms and -Xmx options), did you try some settings with -XX:PermSize and -XX:MaxPermSize (default from 32MB to 64MB depending on JVM version) ?
VonC
Unfortunately I can't change the JVM as this is an embedded system and the vm is used for some other options
Mario Ortegón
+22  A: 

What number, exactly, are you using to say that virtual memory is "too high". Because, in general, that's a meaningless statement, and the virtual memory map contains a lot of things that don't actually consume active system resources.

For example, here's the "top" report for a Java process in my workstation (I think that it's NetBeans):

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
17463 kgregory  20   0  590m 214m  80m S  0.7 14.2  80:39.18 java

There are two numbers there: VIRT, which is the size of the virtual memory map, and RES, which is the amount of RAM consumed (there's also SHR, which is shared memory, but I'm going to focus on the first two).

OK, so if RES is big, in means that there's a lot of physical memory being consumed by your process, and that could interfere with other processes or cause a lot of paging.

The VIRT number, however, is much less meaningful. From the "top" documentation:

The  total  amount  of virtual memory used by the task.  It includes
all code, data and  shared  libraries  plus  pages  that  have  been
swapped out.

What this means is that VIRT includes stuff that's on-disk and rarely/never used. You can see exactly what this is by using the "pmap" command (showing only things loaded from the JDK directory; the full output is 617 lines):

08048000     60K r-x--  /usr/local/java/jdk-1.5/bin/java
08057000      8K rwx--  /usr/local/java/jdk-1.5/bin/java
909b0000   5632K r-xs-  /usr/local/java/jdk-1.5/jre/lib/i386/client/classes.jsa
911b0000   5932K rwx--  /usr/local/java/jdk-1.5/jre/lib/i386/client/classes.jsa
b1462000    384K r-x--  /usr/local/java/jdk-1.5/jre/lib/i386/libawt.so
b14c2000     24K rwx--  /usr/local/java/jdk-1.5/jre/lib/i386/libawt.so
b15ee000     68K r-x--  /usr/local/java/jdk-1.5/jre/lib/i386/libnet.so
b15ff000      4K rwx--  /usr/local/java/jdk-1.5/jre/lib/i386/libnet.so
b1681000   6880K r-xs-  /usr/local/java/jdk-1.5/lib/tools.jar

As you can see, there are many things in the virtual memory map: those that are marked "rwx--" are generally data spaces, while those that are marked "r-x--" are typically disk-resident, and affect your actual RSS/Swap in very indirect ways (tools.jar, for example, is a memory-mapped file; the JVM will access pieces of it in a random manner, and those will move into RSS but never into swap).

(edited to show a better extract from the pmap, with more explanation)

kdgregory
Good remarks. +1
VonC
Thanks, that really helped me understand!
Mario Ortegón
You should take into account that portions of memory which are currently swapped out are missing from the RES measure. So you might have a low RES value but only because the application was inactive and much of the heap was swapped out to disk.Java does a very bad job wrt to swap: On each full GC most of the heap is walked and copied so if much of your heap was in swap, the GC has to load it all back into main memory.
jrudolph
Great answer kdgregory! I'm running in an embedded environment using a CF which has NO swap space. So based on your answer all of my VIRT, SWAP and nFLT values are from memory mapped files... which now makes sense to mew. Do you know if the SWAP value represent pages that have not yet been loaded into memory or pages that have been swapped out of memory, or both? How can we get an idea of possible thrashing (continuous map in then swap out)?
Jeach
@Jeach - I was surprised that any swap was reported, so booted my "traveling Linux" (a thumb drive with Ubuntu 10.04 and no swap). When I enabled the "SWAP" column in *top*, I saw Eclipse had 509m. When I then looked at it with *pmap*, the total virtual space was 650m. So I suspect that the "SWAP" figure represents all on-disk pages, not just those that aren't in memory.
kdgregory
As for your second question: if you're constantly reading pages from the flash card, your IO wait time (shown in the summary of *top* as "%wa") should be high. Beware, however, that this will be high for any activity, particularly writes (assuming that your program does any).
kdgregory
+3  A: 

The amount of memory allocated for the Java process is pretty much on-par with what I would expect. I've had similar problems running Java on embedded/memory limited systems. Running any application with arbitrary VM limits or on systems that don't have adequate amounts of swap tend to break. It seems to be the nature of many modern apps that aren't design for use on resource-limited systems.

You have a few more options you can try and limit your JVM's memory footprint. This might reduce the virtual memory footprint:

-XX:ReservedCodeCacheSize=32m Reserved code cache size (in bytes) - maximum code cache size. [Solaris 64-bit, amd64, and -server x86: 48m; in 1.5.0_06 and earlier, Solaris 64-bit and and64: 1024m.]

-XX:MaxPermSize=64m Size of the Permanent Generation. [5.0 and newer: 64 bit VMs are scaled 30% larger; 1.4 amd64: 96m; 1.3.1 -client: 32m.]

Also, you also should set your -Xmx (max heap size) to a value as close as possible to the actual peak memory usage of your application. I believe the default behavior of the JVM is still to double the heap size each time it expands it up to the max. If you start with 32M heap and your app peaked to 65M, then the heap would end up growing 32M -> 64M -> 128M.

You might also try this to make the VM less aggressive about growing the heap:

-XX:MinHeapFreeRatio=40 Minimum percentage of heap free after GC to avoid expansion.

Also, from what I recall from experimenting with this a few years ago, the number of native libraries loaded had a huge impact on the minimum footprint. Loading java.net.Socket added more than 15M if I recall correctly (and I probably don't).

James Schek
+3  A: 

The Sun JVM requires a lot of memory for HotSpot and it maps in the runtime libraries in shared memory.

If memory is an issue consider using another JVM suitable for embedding. IBM has j9, and there is the Open Source "jamvm" which uses GNU classpath libraries. Also Sun has the Squeak JVM running on the SunSPOTS so there are alternatives.

Thorbjørn Ravn Andersen
Is it an option to disable hot spot?
Mario Ortegón
Perhaps. Check the command line options for the JVM you use.
Thorbjørn Ravn Andersen