A while ago I analyzed problems with assigning object IDs. Back then, I had the following symptoms:
java.lang.Object
: always -1, can’t hold a fieldjava.lang.String
: always -1, can’t hold a fieldjava.lang.Class
: always 0,$$$objectID$$$
field doesn’t get initialized- arrays: always -1
Since then, I have changed the base class implementation to use the identity hashcode instead of -1 to signal if an object ID isn’t available. To distinguish object IDs and identity hashcodes, object IDs are now negative. Let’s look at what the same code generates now:
0 3 // 000030e4 0003 0018 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 1 // 000030e4 0003 0018 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 2 // 000030e4 0003 006c 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 3 // 000031d7 0002 001a 18262862 ObjectIDTest.main 0 1 // 000031d7 0002 001a 18262862 ObjectIDTest.main 0 2 // 000031d7 0002 0047 18262862 ObjectIDTest.main 0 3 // 000030e4 0003 0018 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 1 // 000030e4 0003 0018 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 2 // 000030e4 0003 006c 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 3 // 000031d7 0002 0085 21539363 ObjectIDTest.main 0 1 // 000031d7 0002 0085 21539363 ObjectIDTest.main 0 2 // 000031d7 0002 00b2 21539363 ObjectIDTest.main 0 3 // 000031d7 0002 00ed 2570525 ObjectIDTest.main 0 1 // 000031d7 0002 00ed 2570525 ObjectIDTest.main 0 2 // 000031d7 0002 011a 2570525 ObjectIDTest.main 0 3 // 000031d7 0002 015d 26867996 ObjectIDTest.main 0 1 // 000031d7 0002 015d 26867996 ObjectIDTest.main 0 2 // 000031d7 0002 018a 26867996 ObjectIDTest.main 0 3 // 000030e4 0003 0018 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 1 // 000030e4 0003 0018 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 2 // 000030e4 0003 006c 22413802 sun.misc.Launcher$AppClassLoader.loadClass 0 8 // 00003188 0001 0016 0 java.lang.Character.0 6 // 00003188 0001 0016 0 java.lang.Character. 0 7 // 00003188 0001 005b -443 java.lang.Character. 0 8 // 00003188 0001 0016 0 java.lang.Character. 0 6 // 00003188 0001 0016 0 java.lang.Character. 0 7 // 00003188 0001 005b -444 java.lang.Character. 0 3 // 000031d7 0002 01db -443 ObjectIDTest.main 0 1 // 000031d7 0002 01db -443 ObjectIDTest.main 0 3 // 000031d7 0002 020d -444 ObjectIDTest.main 0 1 // 000031d7 0002 020d -444 ObjectIDTest.main 0 2 // 000031d7 0002 023b -444 ObjectIDTest.main 0 2 // 000031d7 0002 0275 -443 ObjectIDTest.main 0 5 // 000031aa 0015 0032 0 java.lang.Thread.exit
Now all locks are distinguishable, though not always by using object IDs. The only zeros here in this recording occur when object IDs are just being assigned. I can probably still fine-tune this and let a few more classes have object IDs, but this is a major improvement already.
As the occurrence of of sync points with codes 6, 7 and 8 may already suggest, assigning object and thread IDs now generate different sync points for their monitorenter
and monitorexit
opcodes (6 through 8 for object IDs, 9 through 11 for thread IDs) , as previously suggested. Another difference is the presence of the TRYMONITORENTER
sync point before the monitorenter
instruction, which makes deadlock detection possible again, but that has been there for a while.