Skip to main content

Releasing unused heap memory to OS

12 replies [Last post]
spk
Offline
Joined: 2006-01-20
Points: 0

Inspired by http://www.dotnet247.com/247reference/msgs/8/41131.aspx I made simple test (run with -Xmx128m):

import java.awt.GridLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;

public class Test extends JFrame
{
public Test()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);

setLayout(new GridLayout(1, 2));

add(new JButton(new ClickAction()));
add(new JButton(new GCAction()));
pack();
setVisible(true);
}

class ClickAction extends AbstractAction
{
public ClickAction()
{
super("Click!");
}

public void actionPerformed(ActionEvent e)
{
int thirtyMegaByte = 30 * 1024 * 1024;

StringBuilder sb = new StringBuilder(thirtyMegaByte);

for (int i = 0; i < thirtyMegaByte / 10; i++)
sb.append("This10char");
}
}

class GCAction extends AbstractAction
{
public GCAction()
{
super("GC!");
}

public void actionPerformed(ActionEvent e)
{
System.gc();
}
}

/**
* @param args
*/
public static void main(String[] args)
{
new Test();
}
}

App contains two buttons, first allocate approx 60M on very long string, second is used to call System.gc(). Memory was measured using Windows Task Manager.

After starting apps takes 16M. After clicking on first button memory grow up to 77M (physical memory reported by Task Manager on 'Performance' tab goes down by 60M...). Memory stays at this level until second button is clicked few times (one click is not enough). After that memory reported by Task Manager is 16M again (sometimes ~21M).

One more thing - minimizing and restoring app window shrinks reported memory to 5-6M, no matter what previous state was (16M or 77M).

Two questions here:
- why after restoring app takes less memory? Is it means that some graphic-related resources are released? Simple GC (without minimazing and restoring) doesn't have this effect
- shouldn't GC be more aggressive in releasing memory to OS, especially with desktop apps?

Additional thoughts:
To release unused heap memory to OS garbage collecting is needed. If heap isn't filled no GC will be performed. It means that after growing to 70M heap will stay at this level because JVM will see no reason to call gc (at least in my test app). And this way no memory will be released to OS without explicit calling gc.

Workaround? Spawn simple thread, which should be working this way:
1. call System.gc() few times
2. sleep
3. goto 1

Little silly, can interfere with automatic GC, and explicit calling GC is discouraged IIRC...

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
alexlamsl
Offline
Joined: 2004-09-02
Points: 0

Well Sun's JVM does to minor GC scans, so your big String instance should get GCed, then since the free heap space is now >70% (default -XX:maxHeapFreeRatio), heap space would be released - but you'll still leave with ~10MB occupied by the JVM.

With NetBeans 5.0 for example, I've set -XX:minHeapFreeRatio=20 and -XX:maxHeapFreeRatio=25 so instead of having it growing to 90~128MB (-Xmx128M by default) in a few hours' of usage, it is kept around 30~50MB even after a whole week! :)

spk
Offline
Joined: 2006-01-20
Points: 0

I'm aware of min/maxHeapFreeRatio... but then again - GC is needed to shrink heap and eventually relase unused memory...

What do you mean by minor GC scans? In what situation they are triggered?

alexlamsl
Offline
Joined: 2004-09-02
Points: 0

It happens regularly, as far as I can tell.

And this is why WeakReference & SoftReference work as specified.

mthornton
Offline
Joined: 2003-06-10
Points: 0

They happen regularly if the application is actually doing something and generating garbage. The situation described by the original poster is rather artificial and involves an app which is completely idle. The obvious cure in this case is for the app to be minimised which will result in Windows rapidly trimming its working set.

mthornton
Offline
Joined: 2003-06-10
Points: 0

The Mem Usage column in Windows task manager reports the current working set size. This is the amount of memory which your process currently has mapped to physical memory and can be quite different to the amount of memory you have allocated. Minimizing an application has a side effect of clearing the working set (there is an option to prevent this). Thus regardless of how much memory you have allocated, after minimizing the value reported by "Mem Used" will be small.

The amount of (virtual) memory allocated is given by the "VM Size" column.

cowwoc
Offline
Joined: 2003-08-24
Points: 0

FYI: This issue has already been discussed many months ago. It turns out that even Notepad consumes an insane amount of memory according to TaskManager's "VM Size" until it is minimized. Aparently this is a normal WindowsNT+ behavior and for performance reasons they don't shrink the working heap until the application is minimized. For Java to force its VM Size to shrink anyway might entail performance issues vs native applications so we're better off leaving things along (IMHO).

Gili

spk
Offline
Joined: 2006-01-20
Points: 0

Ok, lets assumie that we have 512 MB of physical memory. Lest assume that Windows takes ~150 MB, so ~370 MB is available.

Now start app posted in my first message 6-7 times. Click first button on every app instance. What will happen? System goes swapping. Every Java apps takes 70MB of physical memory, from which 60 MB will be unused. But memory is allocated and 6 x 70 > 370...

So if we want Java apps on desktop this behavior is really not appropiate.

mthornton
Offline
Joined: 2003-06-10
Points: 0

If the memory is allocated but not really in use, then it will drop out of the processes working set. Thus the actual memory load on the system will tend to 6 x 10MB (in your example) which is easily managable.
Also when a full garbage collection cycle takes place it will compact the 10MB still in use into a contiguous section of memory.
So actually returning allocated memory to the OS has only a limited effect on the performance of a system using virtual memory --- any physical memory still mapped to the area being returned will just be released from the working set a little earlier.

spk
Offline
Joined: 2006-01-20
Points: 0

But the issue is that no GC is performed. Thus memory will be not released to OS. Lets see how my program works:

1. Heap is 4 MB (default size IIRC)
2. Big String is allocated - heap too small, GC is performed, still not enough, heap will grow up to ~70 MB.
3. Now created String is discardable, but to do that GC must be performed. And since JVM see no reason to do GC, memory will be not released.
4. End of story.

Prove me wrong (I would be really happy) - but my tests shows that in scenario described in my previous post system goes swapping, since unused heap memory isn't released to OS.

mthornton
Offline
Joined: 2003-06-10
Points: 0

If you aren't using the string, then the memory it occupies will eventually be swapped out by the operating system and then be of no further concern unless you start using it again. How quickly this happens depends on the memory pressure on the OS and its VM management algorithms.

spk
Offline
Joined: 2006-01-20
Points: 0

Yep, eventually... And before it happen system become lagged and inresponsible because of swapping.

forax
Offline
Joined: 2004-10-07
Points: 0