|
Quick Lists
|
|
Bug ID:
|
4646747
|
|
Votes
|
0
|
|
Synopsis
|
Wrong getPersistenceDelegate() return after memory stress
|
|
Category
|
java:classes_beans
|
|
Reported Against
|
1.4
|
|
Release Fixed
|
1.4.1(hopper)
|
|
State
|
10-Fix Delivered,
bug
|
|
Priority:
|
3-Medium
|
|
Related Bugs
|
6582164
|
|
Submit Date
|
04-MAR-2002
|
|
Description
|
FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)
FULL OPERATING SYSTEM VERSION :
customer Windows 2000 [Version 5.00.2195]
A DESCRIPTION OF THE PROBLEM :
XMLEncoder looses custom PersistenceDelegate after
intensive memory allocation. It works as expected under
1.4.0beta3 but fails on 1.4.0RC1.
In the provided test program, I create new 1MB array in
loop and check whether or not getPersistenceDelegate()
returns the same customer , i've put by
setPersistenceDelegate() earlier.
Test output shows, that:
1. on 1.4.0RC1 check fails after third allocation. (because
JVM starts by default with 2M memory pool)
2. on 1.4.0Beta3 check is OK on 10 allocations.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Compile provided class.
2.Run test:
java persistence_test.Test
EXPECTED VERSUS ACTUAL BEHAVIOR :
Output on 1.4.0RC1:
Before memory allocation: OK
0 OK
1 OK
2 Different: persistence_test.Test$1 :
java.beans.DefaultPersistenceDelegate
Test finished
Output on 1.4.0beta3:
Before memory allocation: OK
0 OK
1 OK
2 OK
3 OK
4 OK
5 OK
6 OK
7 OK
8 OK
9 OK
Test finished
Note:
The actual results would depend on how many memory JVM
allocated on startup on your system...
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package persistence_test;
import java.beans.*;
import java.io.*;
public class PersistenceTest {
public static void main(String[] args){
final int ARRAYSIZE = 1000000;
final int BUFERLENGTH = 10;
try{
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(new
ByteArrayOutputStream()));
PersistenceDelegate pd = new DefaultPersistenceDelegate(){
protected Expression instantiate(Object oldInstance, Encoder
out) {
return super.instantiate(oldInstance, out);
}
protected void initialize(Class type, Object oldInstance,
Object newInstance, Encoder out) {
super.initialize(type, oldInstance, newInstance, out);
}
};
encoder.setPersistenceDelegate(Test.class, pd);
Object[] bufArray = new Object[BUFERLENGTH];
System.out.print("Before memory allocation: ");
checkClasses(pd, encoder.getPersistenceDelegate(Test.class));
for(int i=0; i < BUFERLENGTH; i++){
bufArray[i] = new byte[ARRAYSIZE];
System.out.print(i + " ");
if (checkClasses(pd, encoder.getPersistenceDelegate
(Test.class))) break;
}
encoder.close();
System.out.println("Test finished");
}catch(Exception ex){
ex.printStackTrace();
}
}
public static boolean checkClasses(PersistenceDelegate pd1,
PersistenceDelegate pd2){
if (pd1 == pd2)
System.out.println("OK");
else{
System.out.println("Different: " + pd1.getClass().getName()
+ " : " + pd2.getClass().getName());
}
return pd1 != pd2;
}
}
---------- END SOURCE ----------
CUSTOMER WORKAROUND :
The possible ugly work around is increasing JVM startup
memory amount with -Xms key.
(Review ID: 139123)
======================================================================
|
|
Work Around
|
The work around is to maintain Strong references to all the BeanInfo classes that you have set a persistence delegate.
The workaround is encapsulated in the static method setPersistenceDelegate(). When the bug is fixed in 1.4.1, all the extra BeanInfo caching may be removed.
/**
* Sets a persistence delgate on an encoder for a specific class.
*/
public static void setPersistenceDelegate(Encoder encoder, Class cls,
PersistenceDelegate delegate) {
// Workaround for SoftReference BeanInfo bug.
// Staticly hold a stong reference to the BeanInfo to prevent
// Garbage collection due to sweep of Softly referenced BeanInfos.
// This should be fixed for 1.4.1
if (beanInfos == null) {
beanInfos = new HashMap();
}
BeanInfo info = (BeanInfo)beanInfos.get(cls);
if (info == null) {
try {
info = Introspector.getBeanInfo(cls);
} catch (Exception ex) {
System.out.println("BeanInfo exception");
}
beanInfos.put(cls, info);
}
// end workaround
encoder.setPersistenceDelegate(cls, delegate);
}
If this static method and HashMap is in a class called BeanUtils, then in all instances in which you call:
encoder.setPersistenceDelegate(Test.class, pd);
Substitute:
BeanUtits.setPersistenceDelegate(encoder, Test.class, pd);
When the bug is fixed, you can stub out most of the body of the static setPersistenceDelegate() method and keep the last line.
xxxxx@xxxxx 2002-03-04
|
|
Evaluation
|
This represents a serious failure and I am well aware of this bug and will fix it for 1.4.1. I fixed a similar JCK failure for internal PeristenceDelegates (4525285), however, this failure is applicable to user set PersistenceDelegates on the Encoder.
The problem stems from the fix to a showstopper 4508780 in which the static BeanInfo cache had a memory leak. To fix the memory leak, a WeakHashMap was used and so that the keys could be gc'd if there were no strong references left. Another part of the solution involved wrapping the BeanInfo values with SoftReferences. This is the essence of the problem as the SoftReferenced BeanInfos would be lost as the memory of the system is stressed.
A solution would be to reintroduce the original bug (minor memory leak 4291376) and emphasize that the caches can be flushed with existing API on the Introspector: flushCaches(), flushFromCache().
One workaround on a development system is to cache the BeanInfo classes locally so that a Strong reference is maintained. See the work around section for details.
xxxxx@xxxxx 2002-03-04
|
|
Comments
|
Submitted On 22-APR-2003
dlparker2
The left hand column is a waste of
space: "Description", "Workaround", "Evaluation", and "Your
Comments & Work-arounds". Why not keep the color coded
area and make the labels top and centered. Single column,
Submitted On 18-JUL-2003
metasim
Correction to comment above. "Lost" PD was a red-herring.
The real problem was that some of the File instances I was
persisting were from the JFileChooser, which returns a
specialization of java.io.File called
"sun.awt.shell.DefaultShellFolder", and since XMLEncoder
requires delegates for each class in the hierarchy the
correct delegate wasn't getting called.
Submitted On 18-JUL-2003
metasim
I'm still having this problem trying to create a
PersistenceDelegate for java.io.File in java 1.4.1_02:
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build
1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|
|
|
 |