JDK-6835406 : SoftReferences are not being collected before OutOfMemoryError
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: 6u12
  • Priority: P3
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2009-04-29
  • Updated: 2011-02-16
  • Resolved: 2009-06-11
Description
FULL PRODUCT VERSION :
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
Java HotSpot(TM) Client VM (build 1.5.0_09-b03, mixed mode, sharing)

FULL OS VERSION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
SoftReferences are not being collected before OutOfMemoryError only when using the "-server" VM option, this does NOT happen using the client VM.  This is a clear violation of the behavior laid out in the SoftReference.java javadoc:
x
* <p> All soft references to softly-reachable objects are guaranteed to have
 * been cleared before the virtual machine throws an
 * <code>OutOfMemoryError</code>.

I believe this is the same issue seen in defect 4701459, but from what I read the fix for that defect never made it into code for some reason or another.

The code to reproduce this might seem a bit contrived, but it quickly reproduces the same issue that is seen with our caching mechanism only when the "-server" vm option is enabled.

The VM Params to use to reproduce the problem are:
-Xmx1000m -Xms1000m -server



THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Yes

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the main() of the attached code

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected:
SoftReferences are GCed before an OOM Error

Actual:
SoftReferences are not GCed before an OOM Error for the java server VM, works as expected on the client VM
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.lang.ref.SoftReference;
import java.util.List;
import java.util.ArrayList;


public class SoftReferenceError {


	public static void main(String[] args) {

		List<SoftReference> data = new ArrayList<SoftReference>();
		for(int i=0; i<80; i++){
			data.add(new SoftReference(getStrVals(1300000)));
			System.out.println(i);
			System.out.println("Used Memory: " + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000000d));
		}
	}

	private static String[] getStrVals(int len){
		String[] ret = new String[len];
		for (int i = 0; i < len; i++) {
			ret[i] = getString(8);
		}

		return ret;
	}

	/**
	 * A method that generates a string whos member data is not shared
	 */
	private static String getString(int num) {
		StringBuilder sb = new StringBuilder(num);
		for (int i = 0; i < num; i++) {
			sb.append(i);
		}
		return sb.toString();
	}
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Use the client VM, not a very appealing solution for a large server app

Comments
EVALUATION The server and client jvm's use a slightly different policy to clear soft refs. I can clearly see that the server jvm is also clearing soft refs albeit a tad less aggressively than the client. To change the aggressiveness with which the server jvm clears soft refs, please use -XX:SoftRefLRUPolicyMSPerMB=... The default setting is 1000 ms/MB of free space. Setting it to something lower like 1 will show the space being cleared more quickly. I am therefore inclined to close this as "not a bug" after checking with the submitter.
20-05-2009

WORK AROUND -XX:-UseGCOverheadLimit
20-05-2009