I have devised a fairly simple example which exhibits this
memory-retention problem (plus my fix):
Instructions (presuming that js.jar is already in your CLASSPATH):
1. Compile the attached java file:
javac ClassCacheMemoryExample.java
2. After ensuring that the current directory is also in your CLASSPATH,
run the generated class:
java ClassCacheMemoryExample
This should generate a message along the following lines:
"In order to try to generate the anticipated OutOfMemoryException,
please add the following jre param: -Xmx32M"
(note the value for -Xmx parameter might vary according to your JRE).
3. Using the above advice, run the following:
java -Xmx32M ClassCacheMemoryExample
Verify that it causes an OutOfMemoryException.
4. Add the following parameter "-customWrapFactory", in order to use the
custom WrapFactory:
java -Xmx32M ClassCacheMemoryExample -customWrapFactory
Verify that that this does NOT cause an OutOfMemoryException.
Consult the attached java for more details of the the test and the "fix".
Kieran
import org.mozilla.javascript.*;
public class ClassCacheMemoryExample {
public static void main (String [] args)
throws Exception
{
final boolean customWrapFactory = args.length>0 &&
args[0].equals("-customWrapFactory");
Context cx = Context.enter();
// create and seal the shared scope.
// nb the sealing isn't actually relevant to the example.
final ScriptableObject sharedScope = cx.initStandardObjects();
sharedScope.sealObject();
if (customWrapFactory) {
// Use our own wrap factory, extending WrapFactory,
that simply
// passes all function calls to the super-class, but
... replacing
// scope with our sharedScope.
WrapFactory ourWrapFactory = new WrapFactory () {
public Object wrap(Context cx, Scriptable
scope, Object obj, Class staticType)
{
return super.wrap(cx, sharedScope, obj,
staticType);
}
public Scriptable wrapAsJavaObject(Context cx,
Scriptable scope, Object javaObject, Class staticType)
{
return super.wrapAsJavaObject(cx,
sharedScope, javaObject, staticType);
}
public Scriptable wrapNewObject(Context cx,
Scriptable scope, Object obj)
{
return super.wrapNewObject(cx,
sharedScope, obj);
}
};
cx.setWrapFactory(ourWrapFactory);
}
// The javscript we're going to run. Concocted in order to use
a lot of memory.
final String js = "var arr = new Array(); for (var
i=0;i<1024*1024;i++) { arr[i] = i; }";
// The scope we'll use for running our script.
Scriptable newScope;
/* Iteration 1. */
// Create a new scope, and set its parent/prototype as per:
//
https://developer.mozilla.org/En/Rhino_documentation/Scopes_and_Contexts#Sharing_Scopes
newScope = cx.newObject(sharedScope);
newScope.setPrototype(sharedScope);
newScope.setParentScope(null);
// Define a new class; Any old java class will work for this
example.
// For simplicity just define a class that extends Object.
class C1 {}
// Wrap the javaclass.
cx.javaToJS(new C1(), newScope); // HERE is where newScope gets
added to the ClassCache (associated with the C1 class)
// Then, run the javascript.
cx.evaluateString(newScope, js, "<script1>", 1, null); // HERE
is where newScope gets lots of memory assigned to it.
/* Iteration 2. */
// Repeat Iteration 1, but with a different wrapped class
newScope = cx.newObject(sharedScope);
newScope.setPrototype(sharedScope);
newScope.setParentScope(null);
class C2 {}
cx.javaToJS(new C2(), newScope); // HERE is where newScope gets
added to the ClassCache (associated with the C2 class)
cx.evaluateString(newScope, js, "<script2>", 1, null); // HERE
is where newScope gets lots more memory assigned to it.
System.out.println("Successfully ran script1 & script2");
if (!customWrapFactory) {
// We're trying to have caused an OutOfMemoryException
by the time
// we get to here.
// Therefore work out how much memory we have in the
heap, and use
// it to suggest a better value for -Xmx.
Runtime r = Runtime.getRuntime();
r.gc(); r.gc();
long approxUsedMem = (r.totalMemory()-r.freeMemory()) /
(1024*1024);
System.out.println("In order to try to generate the
anticipated OutOfMemoryException, please add the following jre param: -Xmx" +
(approxUsedMem*3/4)+ "M");
}
cx.exit();
}
}
_______________________________________________
dev-tech-js-engine-rhino mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-js-engine-rhino