|
Quick Lists
|
|
Bug ID:
|
4699981
|
|
Votes
|
98
|
|
Synopsis
|
ClassCircularityError thrown without reason during class loading
|
|
Category
|
java:runtime
|
|
Reported Against
|
1.4
, 1.4.2
|
|
Release Fixed
|
mustang(b51),
5.0u8(b01) (Bug ID:2139628)
|
|
State
|
10-Fix Delivered,
bug
|
|
Priority:
|
3-Medium
|
|
Related Bugs
|
6341374
,
6182639
,
4940739
,
4670071
|
|
Submit Date
|
10-JUN-2002
|
|
Description
|
FULL PRODUCT VERSION :
java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)
and
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 :
This problem happens both in JDK 1.3.1 and in 1.4.0,
Windows 2000.
When 2 threads are loading the same class with the same
classloader, and somehow one of the 2 threads releases the
synchronization lock on the classloader, the JVM code
throws ClassCircularityError, mistakenly.
Refer to the JVM class (in systemDictionary.cpp) and method
SystemDictionary::resolve_instance_class_or_null(...) for
where the bug is originating.
Refer also to RFE #4670071. As explained there, in JBoss
3.0 (http://www.jboss.org) a new classloading model is
used, not based on the tree model, that gives important
features such as hot-deploy and modularity. Because of the
synchronization on the classloader, JBoss' classloading
model (or any other classloading mechanism not based on the
tree model) may suffers of deadlocks. In JBoss 3.0 the
deadlock issue has been resolved, releasing the classloader
lock, but this solution showed up the ClassCircularityError
bug, this time in JVM code, and hence with no solution.
Probably the JVM code should throw ClassCircularityError if
a placeholder is found by the same thread that put it, not
if another thread is coming in asking for the same class
with the same classloader.
Note that the problem originates by calls that trigger a
call to the native code in
SystemDictionary::resolve_instance_class_or_null(...); from
investigation I was able to find these methods:
1. Class.defineClass
2. Class.loadClassInternal
3. Class.newInstance (and Constructor.newInstance)
4. Class.forName
There may be other, the code submitted only shows the
problem with 3., but in JBoss the problem is seen it with
all of the 4 cases listed above.
In the code submitted, URLClassLoader has been subclassed
only to make a reproducible test case, but in real code
there is no need to subclass it to get the problem (only
will happen only in certain situation/thread timing).
It would be nice that this bug and RFE #4670071 will go on
in parallell, to give more freedom to the classloading
mechanism.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Make 4 files of the submitted code, namely Base.java,
Derived.java, Support.java and Main.java.
2. Compile the files, for example in directory classes/
3. java -cp classes Main
EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected result: no errors, the 2 threads are able to load
the classes
Actual Result: ClassCircularityError is thrown.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.ClassCircularityError: Base
at Support.<init>(Support.java:7)
at java.lang.Class.newInstance0(Native Method)
at java.lang.Class.newInstance(Class.java:237)
at Main$Run1.run(Main.java:97)
at java.lang.Thread.run(Thread.java:484)
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class Base {}
public class Derived extends Base {}
public class Support
{
private Base base = new Base();
}
import java.net.URL;
import java.net.URLClassLoader;
/**
*
* @version $Revision$
*/
public class Main
{
public static void main(String[] args) throws Exception
{
new Main();
}
private Object lock = new Object();
public Main() throws Exception
{
URL location = getClass().getProtectionDomain().getCodeSource
().getLocation();
URLLoader loader = new URLLoader(new URL[] {location}, getClass
().getClassLoader().getParent());
Class cls = loader.loadClass("Support");
Thread t1 = new Thread(new Run1(cls));
t1.start();
Thread.sleep(1000);
// Load Derived, will trigger a loadClassInternal for Base
loader.loadClass("Derived");
}
public class URLLoader extends URLClassLoader
{
private boolean m_firstTime = true;
public URLLoader(URL[] urls, ClassLoader parent)
{
super(urls, parent);
}
public Class loadClass(String name) throws ClassNotFoundException
{
if (name.equals("Base"))
{
if (m_firstTime)
{
m_firstTime = false;
// Notify the other thread
synchronized (lock)
{
lock.notifyAll();
}
// Wait on the classloader to have the JVM throw
ClassCircularityError
try
{
synchronized (this)
{
wait(5000);
}
}
catch (InterruptedException ignored)
{
}
}
}
return super.loadClass(name);
}
}
public class Run1 implements Runnable
{
private Class cls;
public Run1(Class cls)
{
this.cls = cls;
}
public void run()
{
synchronized (lock)
{
try
{
lock.wait();
}
catch (InterruptedException ignored) {}
}
// Trigger loadClassInternal for Base
try
{
cls.newInstance();
}
catch (Throwable x)
{
x.printStackTrace();
}
}
}
}
---------- END SOURCE ----------
CUSTOMER WORKAROUND :
None, unfortunately.
(Review ID: 148304)
======================================================================
Posted Date : 2005-09-02 12:52:02.0
|
|
Work Around
|
N/A
|
|
Evaluation
|
Testcase can be found at: /net/curious-george.east/disk2/Tests/4699981
xxxxx@xxxxx 2002-06-11
-------------------------------------------------------------------------
xxxxx@xxxxx 2002-06-17
Sequence of events:
+ the main thread M runs the method main.
+ thread M creates class loader L.
+ thread M uses L to load class Support (and returns).
+ thread M creates a new thread R passing the Class object for Support,
and sleeps, giving thread R a chance to run.
+ thread R blocks waiting for the Lock object to be notified.
+ thread M uses L to load class "Derived",
+ which requires L to load superclass Base,
>> A "placeholder" of <Base,L> is added to the system dictionary.
+ during which thread R is notified via the Lock object.
and sleeps, giving thread R a chance to run.
+ thread R creates an instance of Support,
+ which requires loader L to load class Base.
>> At this point, both thread M and thread R are executing in the
loadClass method in L at the same time.
>> thread R, attempting to load Base, finds the placeholder for Base,
and declares the circularity error.
>> thread M: loadClass("Derived")
>> -> defineClass("derived")
>> -> VM
>> -> loadClass("Base")
>> thread R:
>> newInstance("Support")
>> -> Support.<init>
>> -> VM [newInstance "Base"]
>> -> loadClass("Base")
Problem:
The purpose of the placeholder is to allow detection of the circularity
error during the loading of a sequence of classes by a single thread.
Thread M should have the classloader lock until after Base is defined.
Thread R should have been held off until Thread M releases the lock.
-------------------------------------------------------------------------
xxxxx@xxxxx 2002-06-20
Since the Main thread gives up its classloader lock when it calls wait(),
this is not a locking bug. In fact, this is a significant indication that
the classloader should never have been locked in the first place.
See bug 4670071 - ClassLoader.loadClassInternal(String) is too restrictive
Fix needed - adjust the "placeholder" scheme so that circularity checks
are handled by individual threads.
------------------------------
A flaw with the proposal of simply not throwing the Circularity error
if the loading wasn't initiated by a particular thread is that true
circularity errors could result in infinite looping in the JVM.
Consider a ClassLoader which always spawns a new thread before calling
defineClass.
If we have Class A which extends Class B, which extends Class A, we'd
see a sequence something like:
Thread1 initiates loading of A, resolves its super classes,
calls loadClassInternally for B. LoadClass spawns a new thread
Thread2 defines B, resolves its supers, calls loadClassInternally for A,
loadClass spawns a new thread
Thread3 defines A, resolves its supers...
This can be overcome by some internal structuring of how the JVM
actually resolves classes and their super classes and super interfaces.
As noted in comments above and the problem description, the root cause
of this problem is the ClassLoader lock being released during class loading.
xxxxx@xxxxx 2002-10-08
We're working on a fix for this problem within the VM.
A fix has been added to Jboss 3.2.3 .
xxxxx@xxxxx 2004-04-09
|
|
Comments
|
Submitted On 27-JUN-2002
chaves
We found the same problem using JBoss 3 running on the
following build on Linux (Red Hat 7.2):
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)
Submitted On 25-JUL-2002
JawwadHussain
I have found this problem using JBoss-3.0.1RC1 running on
Solaris 2.6 with Sun JDK 1.1.3_01
Submitted On 31-JUL-2002
mcli
It would be very nice if this bug is fixed soon. We recently
transitioned to JBoss 3.0.0 and have encountered this problem
as well. We are using the Java 1.3.1_03 JVM with Solaris 8,
Windows NT and Windows 2000.
Submitted On 31-JUL-2002
tunnu_98
we found same problem with JDK 1.4.0_01-ea-b02 on
Windows 2000, JBoss 3.0.0
Submitted On 01-AUG-2002
dnouls
I have the same problem with JBoss 3.0.1 RC1 and JRE 1.3.1_004 on Windows 2000 SP3
java version "1.3.1_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_04-b02)
Java HotSpot(TM) Client VM (build 1.3.1_04-b02, mixed mode)
Submitted On 07-AUG-2002
camyhsu
Same problem on the following config:
JBoss 3.0.0
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build
1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)
RedHat Linux 7.x
Submitted On 18-AUG-2002
nishacharan
We found this problem while using JBoss 3.0 on Windows NT
4.0 SP6. JDK details are :
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build
1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)
Submitted On 21-AUG-2002
toddhuss
I'm using the latest Java build 1.4.1-rc-b19 for Linux as of
August 21st and this problem still occurs.
Submitted On 05-MAR-2003
bernatl
I've found this problem using JRun4, AIX 4.3 & JDK1.3.1
Submitted On 13-NOV-2003
Kevin_S2955
Same issue as others error encountered on JBoss 3.0 on HPUX
Submitted On 13-NOV-2003
Kevin_S2955
Same issue as others error encountered on JBoss 3.0 on HPUX
Submitted On 22-MAR-2004
y_sameer
We are also facing this problem in JBoss 3.2.2RC3
and j2sdk1.4.1_02 in both Windows 2000 and Solaris
platforms and it is creating a serious problem in our
concurrency tests.
Submitted On 08-APR-2004
DrThaneMD
Curious... Any progress with this bug? If so, what
release version might it be on? Some of us in the
production world have to answer to this bug. Having
some sort of "real" answer, short of silence, would be
highly appreciated.
Submitted On 23-NOV-2004
break11
Well, we use 3.2.3 in production and we
Submitted On 21-MAR-2005
karl_fenwick
We're currently at System Integration and using Java VM: Java HotSpot(TM) Client VM 1.4.2_05-b04,Sun Microsystems Inc with JBoss [Zion] 4.0.1RC1 (build: CVSTag=JBoss_4_0_1_RC1 date=200411041143). Is there a fix or work around available yet? Our product has a high availabity requirement and this is causing us a major headache.
Submitted On 20-AUG-2006
Mr_Galder
Fixed in J2SE(TM) Development Kit 5.0 Update 8
Submitted On 16-OCT-2008
jdupl
We have also just encountered this....
JBOSS: Release ID: JBoss [Zion] 4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)
Java version: 1.4.2_18,Sun Microsystems Inc.
Java VM: Java HotSpot(TM) Server VM 1.4.2_18-b06,Sun Microsystems Inc.
OS-System: Linux 2.6.18-53.el5,i386 (Red Hat Enterprise Linux Server release 5.1 (Tikanga))
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|
|
|
 |