HashMap implementations and Integer specializations

charlie hunt charlie.hunt at sun.com
Mon Jun 9 18:26:40 UTC 2008


Martin,

I'm rather shocked at your response!

Consider for example, there's a very popular tool out their that 
integrates very well into NetBeans  IDE and Eclipse IDE which suggests 
changing all 'new Integer(), new Long()' calls into 'Integer.valueOf() & 
Long.valueOf()'.  Take a quick look at how new Integer() contrasts with 
Integer.valueOf().

Suppose in the future as Martin moves on to bigger and better things 
beyond OpenJDK and a future maintainer looks at your test case and 
updates it to use Integer.valueOf() and Long.valueOf() as result of such 
a tool mentioned above.   Should that happen, I don't think your test 
case would test what it was intended to test.

Would not your test case be improved by choosing values well outside the 
values contained in the IntegerCache & LongCache?

charlie ...

Martin Buchholz wrote:
> Charlie,
>
> Hotspot engineers throughout the ages
> have been tempted to optimize away
> object identity semantics of Integer and String,
> but I'm pretty sure that for e.g. new Integer(x)
> and new String(y) hotspot will certainly continue
> to return _new_ objects (unless of course
> the application can be proven to not tell the
> difference), and there are sufficient
> regression tests to keep all of us in line.
>
> Martin
>
> On Mon, Jun 9, 2008 at 7:57 AM, charlie hunt <charlie.hunt at sun.com> wrote:
>   
>> wrt the Integer & Long values you use in your test case ...
>>
>> You might consider using larger Integer & Long values, ones that lie outside
>> the range of Integer.IntegerCache & Long.LongCache to avoid any potential
>> confusion about whether the values you are putting into the Map might get
>> grabbed from the IntegerCache or LongCache via some "magic" of the HotSpot
>> compiler, i.e it's conceivable a call to 'new Integer()' could be
>> transformed into Integer.valueOf()'.
>>
>> charlie ...
>>
>> Martin Buchholz wrote:
>>     
>>> JavaOne 2008 technical session PDFs are now available
>>>
>>>
>>> http://developers.sun.com/learning/javaoneonline/j1online.jsp?track=javase&yr=2008
>>>
>>> I was surprised to discover a discussion of
>>> HashMap optimization at the JavaOne talk
>>> http://developers.sun.com/learning/javaoneonline/2008/pdf/TS-6434.pdf
>>>
>>> Did I miss an announcement of that?
>>>
>>> A comment on that talk:
>>>
>>> It is easy to make the mistake of thinking that HashMap does not
>>> have to store the actual Integer key in the call to put.
>>> Unfortunately, Java's evil semantics (everything is an Object,
>>> everything is a Lock, everything has an Identity) require
>>> that the exact same objects inserted into a HashMap can be
>>> removed later.  This means that specialized submaps will have
>>> a harder time optimizing for footprint.  (I do think the
>>> algorithm presented in the talk is correct, since the front cache
>>> is likely only used for get(), and not, e.g. for entrySet().iterator())
>>>
>>> I intend to check in a test case modification that will ensure
>>> that future optimizations do not violate the current compatibility
>>> guarantees.
>>>
>>> diff --git a/test/java/util/Collection/MOAT.java
>>> b/test/java/util/Collection/MOAT.java
>>> --- a/test/java/util/Collection/MOAT.java
>>> +++ b/test/java/util/Collection/MOAT.java
>>> @@ -544,6 +544,27 @@ public class MOAT {
>>>         check(m.size() != 0 ^ m.isEmpty());
>>>     }
>>>
>>> +    private static void testPutPreversesObjectIdentity(Map<?,?> m,
>>> +                                                       Object key,
>>> +                                                       Object val) {
>>> +        try {
>>> +            Map<Object,Object> m2 = m.getClass().newInstance();
>>> +            m2.put(key, val);
>>> +            Map.Entry<Object,Object> e = m2.entrySet().iterator().next();
>>> +            check(e.getKey()   == key);
>>> +            check(e.getValue() == val);
>>> +            check(m2.keySet().iterator().next() == key);
>>> +            check(m2.values().iterator().next() == val);
>>> +        } catch (Throwable t) { unexpected(t); }
>>> +    }
>>> +
>>> +    private static void testPutPreversesObjectIdentity(Map<?,?> m) {
>>> +        testPutPreversesObjectIdentity(m, new Integer(42),  new
>>> Integer(43));
>>> +        testPutPreversesObjectIdentity(m, new Long(42L),    new
>>> Long(43L));
>>> +        testPutPreversesObjectIdentity(m, new Double(42.0), new
>>> Double(43.0));
>>> +        testPutPreversesObjectIdentity(m, new String("42"), new
>>> String("43"));
>>> +    }
>>> +
>>>     private static void testMap(Map<Integer,Integer> m) {
>>>         System.out.println("\n==> " + m.getClass().getName());
>>>
>>> @@ -572,6 +593,7 @@ public class MOAT {
>>>         }
>>>
>>>         if (supportsPut(m)) {
>>> +            testPutPreversesObjectIdentity(m);
>>>             try {
>>>                 check(m.put(3333, 77777) == null);
>>>                 check(m.put(9134, 74982) == null);
>>>
>>>       
>> --
>>
>> Charlie Hunt
>> Java Performance Engineer
>>
>> <http://java.sun.com/docs/performance/>
>>
>>
>>     

-- 

Charlie Hunt
Java Performance Engineer

<http://java.sun.com/docs/performance/>




More information about the core-libs-dev mailing list