you are forgetting that the value that is stored is also in mem So if the value is an Integer object that is again an 4 bytes ci, 4 bytes oi and 4 bytes value
But the IntHashmap is far from complex, i even like it if i just have int -> value (which is where it is used for) else i have to wrap those ints in a Integer object first (or auto box it which i dont like to much) so it is a big quicker, its smaller in mem size, and is easier to use when you just have int keys.. i dont see any drawback johan On Fri, Feb 13, 2009 at 19:42, Tuomas Kärkkäinen <[email protected]>wrote: > Hi, > > The int in Entry is a 32bit value so it takes 4 bytes of memory. > > In a 32bit JVM, a reference, ie. a pointer takes 4 bytes. In a 64bit JVM > it takes 8 bytes. > > HashMap's Entry consumes on a 32bit jvm: > 4 bytes for the class identifier, > 4 bytes for the object identifier, > 4 bytes for the key > 4 bytes for the value > 4 bytes for the hash > 4 bytes for next > > a total of 24 bytes. > > and on a 64bit jvm > 4 bytes for the class identifier, > 4 bytes for the object identifier, > 8 bytes for the key > 8 bytes for the value > 4 bytes for the hash > 8 bytes for next > > 36 bytes. > > IntHashMap's entry takes: > 4 bytes for the class identifier, > 4 bytes for the object identifier, > 4 bytes for key > 4 bytes for value > 4 bytes for next > 20 total on 32bits > or > 4 bytes for the class identifier, > 4 bytes for the object identifier, > 4 bytes for key > 8 bytes for value > 8 bytes for next > 28 total on 64bits > > java.util.AbstractMap$SimpleEntry<K,V> and consequently > java.util.concurrent.ConcurrentHashMap$WriteThroughEntry > only has serialVersionUID, key and value. > which is 24 bytes on 32bit and 32bytes on 64bit. > > As an aside, on my core2, the 32-bit hotspot seems to align objects on > 8byte boundaries, so 20 and 24 bytes both consume 24 bytes. > > My personal conclusion would be that if there is a memory saving advantage > to using IntHashMap, it is negligible. Further, the accidental complexity > IntHashMap introduces outweighs the memory savings. > > Br, > Tuomas > > Quoting Johan Compagner <[email protected]>: > > the serialized size doesnt have to be that different if you use Integer >> key >> objects because hashmap has its own special serialization where it doesnt >> have to store everything thats in mem >> but just the key/value combination >> >> >> But in memory we have an Entry object: >> >> HashMap.Entry implements Map.Entry { >> final Object key; >> Object value; >> final int hash; >> Entry next; >> >> IntHashMap.Entry >> { >> final int key; >> Object value; >> Entry next; >> >> so you see thats one reference less per entry. >> >> Also the lookup could be faster because it doesnt have to calculate the >> hash >> on for example strings. >> >> The IntHashMap just skips over the object key hash and gives you the >> option >> to give that hash yourself. >> This only works ofcourse for the same type of objects where the hash is >> always different for any object, so it wont work as a replacement of >> String >> key, but it does for Integer key >> >> johan >> >> >> On Fri, Feb 13, 2009 at 09:43, Tuomas Kärkkäinen < >> [email protected]>wrote: >> >> >> Hi, >>> >>> I couldn't gather from the javadoc when IntHashMap should be preferred >>> over >>> a regular HashMap, i.e. how many objects per map, what type of objects >>> etc. >>> >>> I wrote a little program (copy pasted at the bottom) to see how much the >>> size difference was for IntHashMap, java.util.HashMap and >>> java.util.concurrent.ConcurrentHashMap. >>> >>> for 1 instance of new org.apache.wicket.Page(){}; >>> for 10 instances of new org.apache.wicket.Page(){}; >>> for 100 instances of new >>> org.apache.wicket.ajax.form.AjaxFormSubmitTestPage(); >>> >>> Br, >>> Tuomas >>> >>> the results are as follows, respectively: >>> >>> -------------------------------------------------- >>> >>> map implementation: org.apache.wicket.util.collections.IntHashMap -- size >>> of outputstream: 54 bytes. >>> map implementation: java.util.HashMap -- size of outputstream: 57 bytes. >>> map implementation: java.util.concurrent.ConcurrentHashMap -- size of >>> outputstream: 282 bytes. >>> HashMap is 5.556% larger than IntHashMap. >>> ConcurrentHashMap is 422.222% larger than IntHashMap. >>> >>> -- >>> >>> map implementation: org.apache.wicket.util.collections.IntHashMap -- size >>> of outputstream: 369 bytes. >>> map implementation: java.util.HashMap -- size of outputstream: 399 bytes. >>> map implementation: java.util.concurrent.ConcurrentHashMap -- size of >>> outputstream: 624 bytes. >>> HashMap is 8.130% larger than IntHashMap. >>> ConcurrentHashMap is 69.106% larger than IntHashMap. >>> >>> -- >>> >>> map implementation: org.apache.wicket.util.collections.IntHashMap -- size >>> of outputstream: 24272 bytes. >>> map implementation: java.util.HashMap -- size of outputstream: 24572 >>> bytes. >>> map implementation: java.util.concurrent.ConcurrentHashMap -- size of >>> outputstream: 24797 bytes. >>> HashMap is 1.236% larger than IntHashMap. >>> ConcurrentHashMap is 2.163% larger than IntHashMap. >>> >>> >>> ---------- >>> >>> /* >>> * Licensed to the Apache Software Foundation (ASF) under one or more >>> * contributor license agreements. See the NOTICE file distributed with >>> * this work for additional information regarding copyright ownership. >>> * The ASF licenses this file to You under the Apache License, Version >>> 2.0 >>> * (the "License"); you may not use this file except in compliance with >>> * the License. You may obtain a copy of the License at >>> * >>> * http://www.apache.org/licenses/LICENSE-2.0 >>> * >>> * Unless required by applicable law or agreed to in writing, software >>> * distributed under the License is distributed on an "AS IS" BASIS, >>> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >>> implied. >>> * See the License for the specific language governing permissions and >>> * limitations under the License. >>> */ >>> package org.apache.wicket.util.collections; >>> >>> >>> import java.io.IOException; >>> import java.util.HashMap; >>> import java.util.concurrent.ConcurrentHashMap; >>> >>> import org.apache.wicket.Page; >>> import org.apache.wicket.util.io.ByteArrayOutputStream; >>> import org.apache.wicket.util.io.WicketObjectOutputStream; >>> import org.apache.wicket.util.tester.WicketTester; >>> >>> public class Tester >>> { >>> private static final int NUMBER_OF_PAGES = 1; >>> >>> >>> public static void main(String[] args) throws Exception >>> { >>> int intHashMapSize = writeMap(populatedIntHashMap()); >>> int hashMapSize = writeMap(populatedHashMap()); >>> int concurrentHashMapSize = >>> writeMap(populatedConcurrentHashMap()); >>> double hashMapIsLargerPercetange = >>> ((Double.valueOf(hashMapSize) / intHashMapSize) - 1) * 100; >>> double concurrentHashMapIsLargerPercetange = >>> ((Double.valueOf(concurrentHashMapSize) / intHashMapSize) - 1) * 100; >>> System.out.printf("HashMap is %.3f%% larger than >>> IntHashMap.%n", hashMapIsLargerPercetange); >>> System.out.printf("ConcurrentHashMap is %.3f%% larger than >>> IntHashMap.%n", >>> concurrentHashMapIsLargerPercetange); >>> } >>> >>> private static int writeMap(Object map) throws IOException >>> { >>> ByteArrayOutputStream out = new ByteArrayOutputStream(); >>> WicketObjectOutputStream objectOutputStream = new >>> WicketObjectOutputStream(out); >>> objectOutputStream.writeObject(map); >>> System.out.printf("map implementation: %s -- size of >>> outputstream: %d bytes.%n", >>> map.getClass().getName(), out.size()); >>> return out.size(); >>> } >>> >>> private static HashMap<Integer, Page> populatedHashMap() >>> { >>> new WicketTester(); >>> HashMap<Integer, Page> map = new HashMap<Integer, Page>(); >>> for (int i = 0; i < NUMBER_OF_PAGES; i++) >>> { >>> map.put(i, createPage()); >>> } >>> return map; >>> } >>> >>> private static ConcurrentHashMap<Integer, Page> >>> populatedConcurrentHashMap() >>> { >>> new WicketTester(); >>> ConcurrentHashMap<Integer, Page> map = new >>> ConcurrentHashMap<Integer, Page>(); >>> for (int i = 0; i < NUMBER_OF_PAGES; i++) >>> { >>> map.put(i, createPage()); >>> } >>> return map; >>> } >>> >>> >>> private static IntHashMap<Page> populatedIntHashMap() >>> { >>> new WicketTester(); >>> IntHashMap<Page> map = new IntHashMap<Page>(); >>> for (int i = 0; i < NUMBER_OF_PAGES; i++) >>> { >>> map.put(i, createPage()); >>> } >>> return map; >>> } >>> >>> >>> private static Page createPage() >>> { >>> Page page = new Page() >>> { >>> }; >>> page.detach(); >>> return page; >>> >>> } >>> } >>> >>> >>> Igor Vaynberg wrote: >>> >>> exactly what the javadoc says, its a map that does not need to store a >>>> key object. so it is smaller than a regular hashmap when serialized or >>>> kept in memory. >>>> >>>> -igor >>>> >>>> On Thu, Feb 12, 2009 at 1:40 PM, Tuomas Kärkkäinen >>>> <[email protected]> wrote: >>>> >>>> Hi, >>>>> >>>>> I was looking at IntHashMap in wicket trunk. >>>>> >>>>> I couldn't figure out what it does. >>>>> >>>>> The implementation of hashcode for Integer is value, and the autoboxing >>>>> of >>>>> int to Integer comes out to Integer.valueOf(int) which is implemented >>>>> as >>>>> an >>>>> array lookup for Integers in the range of -128 to 127, and beyond that >>>>> it's >>>>> just new Integer(int). Page ids start at zero for each page in each >>>>> session >>>>> so most of the time they will be between zero and 127. >>>>> >>>>> Br, >>>>> Tuomas >>>>> >>>>> >>>>> >>>>> >>> >> > >
