Duplicate :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
The following problems happen on jdk 1.4.1, 1.4.2, 1.5.0 . Exact steps to reproduce the problem. JCK test javasoft.sqe.tests.api.java.awt.Color.getColorSpaceTests fails intermittently with java.awt.color.ProfileDataException when running with "ScavengeALot" option. The following script can be used to reproduce the problem: ---------------------------------------------- set -x #!/bin/sh JHOME=/opt/jdk142 JCK_CLASSES=/proj/tests/java/jck/JCK-14a.fcs/JCK-runtime-14a/classes let n=0 let p=0 let f=0 let e=0 #exclude sun/awt/color/ICC_Transform.<init> #exclude java/awt/color/ICC_ColorSpace.toRGB while [ $n -ne 1 ] do let n=$n+1 echo "+++++++++++++++++++++++ $0 / $n / $p / $e +++++++++++++++++++++++" $JHOME/bin/java_g \ -XX:+ScavengeALot \ -XX:ScavengeALotInterval=2 \ -XX:InitialTenuringThreshold=100 \ -XX:MaxTenuringThreshold=200 \ -XX:-UseParallelGC \ -Xfuture \ -Xcomp \ -classpath $JCK_CLASSES \ javasoft.sqe.tests.api.java.awt.Color.getColorSpaceTests -TestCaseID Color0024 status=$? echo "Status = $status" if [ $status -eq 95 ] then let p=$p+1 else if [ $status -eq 97 ] then let e=$e+1 break else let f=$f+1 break fi fi done echo "Failed on run $n, exeception = $e" ---------------------------------------------- The test can be made to fail consistently by putting a System.gc() call in sun.awt.color.ICC_Transform class's third constructor (the one that takes an array of ICC_Transform as argument) right before the call to CMM.cmmCombineTransforms(). . Exact text of any error message(s). Color0023: Passed. OKAY java.awt.color.ProfileDataException: Invalid profile sequence at sun.awt.color.ICC_Transform.<init>(ICC_Transform.java:115) at java.awt.color.ICC_ColorSpace.toRGB(ICC_ColorSpace.java:148) at java.awt.Color.<init>(Color.java:516) at javasoft.sqe.tests.api.java.awt.Color.getColorSpaceTests.Color0024(getColorSpaceTests.java:101) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at javasoft.sqe.javatest.lib.MultiTest.invokeTestCase(MultiTest.java:399) at javasoft.sqe.javatest.lib.MultiTest.run(MultiTest.java:195) at javasoft.sqe.javatest.lib.MultiTest.run(MultiTest.java:127) at javasoft.sqe.tests.api.java.awt.Color.getColorSpaceTests.main(getColorSpaceTests.java:26) Color0024: Failed. Test case throws exception: java.awt.color.ProfileDataException: Invalid profile sequence . Reason for the failure What happened is: In java.awt/color/ICC_ColorSpace: 140 public float[] toRGB (float[] colorvalue) { 141 142 if (this2srgb == null) { 143 ICC_Transform[] transformList = new ICC_Transform [2]; 144 ICC_ColorSpace srgbCS = 145 (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB); 146 transformList[0] = new ICC_Transform ( 147 thisProfile, ICC_Transform.Any, ICC_Transform.In); 148 transformList[1] = new ICC_Transform ( 149 srgbCS.getProfile(), ICC_Transform.Any, ICC_Transform.Out); 150 this2srgb = new ICC_Transform (transformList); 151 if (needScaleInit) { 152 setComponentScaling(); 153 } 154 } 155 ...... 168 } The above method calls ICC_Transform constructor on line 150 and passes in the ICC_Transform array "transformList". Here's what the ICC_Transform constructor looks like: 97 public ICC_Transform ( ICC_Transform[] transforms) 98 { 99 int cmmStatus; 100 long[] transformIDs; 101 int nTransforms, i1; 102 103 nTransforms = transforms.length; 104 105 transformIDs = new long [nTransforms]; 106 107 /* put transform IDs into an array */ 108 for (i1 = 0; i1 < nTransforms; i1++) { 109 transformIDs [i1] = transforms[i1].ID; 110 } 111 112 cmmStatus = CMM.cmmCombineTransforms (transformIDs, this); 113 114 if ((cmmStatus != CMM.cmmStatSuccess) || (ID == 0)) { 115 throw new ProfileDataException ("Invalid profile sequence"); 116 } 117 } This method calls CMM.cmmCombineTransforms() on line 112. CMM.cmmCombineTransforms() is a native method. It uses some native data structures that's associated with the two ICC_Transform objects in the array. It gets the native data structures through "transformIDs". If both of the above java methods are compiled and GC happens when CMM.cmmCombineTransforms is running, the ICC_Transform array and the two objects in the array are not reachable in either of the above two methods, so they are garbage collected, which causes the two ICC_Transform object's finalize() method to run. The ICC_Transform object's finalize() method causes the native data structures that's associated with it to be freed. But the native method is still using them. So the failure happens. It's okay for the compiler and the garbage collector to collect the ICC_Transform array because of the following statements in JSR133 section B.1 "Finalization": "Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would na����vely be considered reachable. For example, a compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner. Another example of this occurs if the values in an object��s fields are stored in registers. The program then may access the registers instead of the object, and never access the object again. This would imply that the object is garbage. " . Proposal for the fix A reasonalbe fix for this problem would be to pass in the array of objects instead of the array of IDs to the native method. That will guarantee that the objects are not garbage collected until the native method completes. Other possible fixes include: 1. private synchronized void keepAlive() {} public ICC_Transform ( ICC_Transform[] transforms) { ... cmmStatus = CMM.cmmCombineTransforms (transformIDs, this); if ((cmmStatus != CMM.cmmStatSuccess) || (ID == 0)) { for (i1 = 0; i1 < nTransforms; i1++) { transforms[i1].keepAlive(); } throw new ProfileDataException ("Invalid profile sequence"); } } public void finalize () { synchronized (this) {} ... } See JSR133 section B.1 "Finalization" for why the "synchronized" statement is needed in the finalizer. 2. Another possible fix would be to, at the end of the method, assign the object array to a volatile static field, then immediately clear it. And then read the volatile static variable at the beginning of the finalizer. Of the above choices of fixes, the first one is preferred. ------------------------------------------------------------- The same test sometime fails for a different reason. ... # An unexpected error has been detected by HotSpot Virtual Machine: # # SIGSEGV (0xb) at pc=cd4e46e0, pid=10403, tid=1 # # Java VM: Java HotSpot(TM) Server VM (1.5.0 Beta2 jinteg:08.16.04- 23:24 IA64 debug compiled mode) # Problematic frame: # C [libcmm_g.so+0xc26e0] fut_lock_fut+0x440 # The reason for the SIGSEGV is that 2 local variables in the PTCombine function in libcmm (combine.c) were uninitialized. What was happening was that the JVM was storing references to the handles allocated during the scavenges on the stack and the address of the local variables in PTCombine was the same as the handle refs. Thus their contents had been polluted (i.e. non-zero) with an address in the handle area. The code in PTCombine passed a pointer to one of these unitialized variables to another function that *only* initializes the value in certain paths. The path we took did not fill a good value in so the contents were still the polluted value. Unfortunately the code in fut_lock_fut only checked if the value passed in was NULL - here it wasn't - but it still wasn't a valid fut_t instance. Initializing PTData1 and PTData2 in PTCombine to NULL stops the SIGSEGV from occuring. Also, it is safer to switch the KpMemSet() call and the unlockPTTable() call at the end of deletePTTable() method, so that we don't zero out PTTable until after unlocking it. ###@###.### 2005-07-11 21:38:00 GMT ###@###.### 2005-07-13 09:52:48 GMT
|