Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two different Class instances giving same hashCode

Tags:

java

ognl

I'm encountering a bizarre issue on a JBoss server where two classes are producing the same hashCode().

Class<?> cl1 = Class.forName("fqn.Class1");
Class<?> cl2 = Class.forName("fqn.Class2");
out.println(cl1.getCanonicalName());
out.println(cl2.getCanonicalName());
out.println(cl1.hashCode());
out.println(cl2.hashCode());
out.println(System.identityHashCode(cl1));
out.println(System.identityHashCode(cl2));
out.println(cl1 == cl2);
out.println(cl1.equals(cl2));
out.println(cl1.getClassLoader().equals(cl2.getClassLoader()));

Produces:

fnq.Class1
fnq.Class2
494722
494722
494722
494722
false
false
true

I normally wouldn't care, but we're using a framework that caches setters using a key that is comprised of hashcodes from the class and a property name. It's a bad design for caching, but it's beyond my control at the moment (OGNL 3.0.6 in the latest Struts 2.3.24, see source. A newer OGNL fixes the issue, but it won't be in Struts until 2.5, currently in beta.)

What makes the issue somewhat bizarre to me is

  • Problem appears after several days of usage... and I'm pretty sure both class/properties are getting cached during that time. This leads me to believe that the class instance hashcode is actually changing... they became equal after several days.
  • We've observed the behavior in a very outdated Hotspot 1.6, and now on 1.7.0_80. Both are 32-bit builds on Sun Sparc
  • JVM reports -XX:hashCode as "0"

I read that the RNG hashcode generator in Hotspot (the "0" strategy) can produce duplicates if there's racing threads, but I can't imagine classloading triggering that behavior.

Does Hotspot use special hashcode handling when creating a Class instance?

like image 754
Glenn Lane Avatar asked Sep 02 '15 03:09

Glenn Lane


People also ask

Can two classes have same hashCode?

HashCode collisions Whenever two different objects have the same hash code, we call this a collision. A collision is nothing critical, it just means that there is more than one object in a single bucket, so a HashMap lookup has to look again to find the right object.

What if two objects returns the same hashCode?

If two objects have the same hashcode then they are NOT necessarily equal. Otherwise you will have discovered the perfect hash function. But the opposite is true: if the objects are equal, then they must have the same hashcode .

What happens if two keys have same hashCode?

When two unequal objects have the same hash value, this causes a collision in the hash table, because both objects want to be in the same slot (sometimes called a bucket).

What happens if hashCode returns constant?

Returns the same hash code for the given object as would be returned by the default method hashCode(), whether or not the given object's class overrides hashCode(). The hash code for the null reference is zero. So even if the hashcode() is overridden, it should not effect it.


1 Answers

  1. java.lang.Class does not override hashCode, nor JVM handles it somehow specially. This is just the regular identity hashCode inherited from java.lang.Object.
  2. When -XX:hashCode=0 (default in JDK 6 and JDK 7) the identity hashCode is calculated using global Park-Miller random number generator. This algorithm produces unique integers with the period of 2^31-2, so there is almost no chance that two objects have the same hashCode except for the reason below.
  3. Since this algorithm relies on a global variable that is not synchronized, there is indeed a possibility that two different threads generate the same random number due to race condition (the source). This is what apparently happens in your case.
  4. Identity hashCode is not generated on object creation, but on the first call to hashCode method. So it does not matter when and how the classes are loaded. The problem can happen with any two objects if hashCode is called concurrently.
  5. I suggest using -XX:hashCode=5 (default in JDK 8). This option uses thread-local Xorshift RNG. It is not subject to race conditions and is also faster than Park-Miller algorithm.
like image 151
apangin Avatar answered Oct 22 '22 03:10

apangin