Discussing this nitpicking has taken time away from fixing bugs, improving things that really matter, running wicket in a profiler, or even helping out on the mailinglist. It serves nothing other than bellybutton gazing. Instead of thinking about how to implement multi window support we have to defend the existence of a class that is useful to us?
This class has its purpose, it is used inside wicket. It has a goal: minimize memory usage. It serves its goal. Is it a maintenance nightmare? no. Does it increase Wicket's conceptual surface? No. Did I know it existed before you brought it up? No. Do I need it in my day-to-day Wicket coding? No. Does it get in the way in my day-to-day Wicket coding? No. Does it increase my time spent on supporting Wicket? No, unless someone starts complaining that it exists. Martijn On Fri, Feb 13, 2009 at 10:15 PM, Tuomas Kärkkäinen <[email protected]> wrote: > Igor, > > Wicket is the best way to develop web applications and I appreciate every > day the wonderful work you, Johan and others are doing. But, I would love to > see Wicket focus on the essentials of web development. This would make it > easier to reason about the functioning of Wicket, and it would make it > easier to contribute bug fixes, improvements, patches etc. > > If the purpose of IntHashMap is to provide the functionality of: > > public class IntHashMap<V> extends HashMap<Integer,V> { > V put(int i, V value) { > return super.put(Integer.valueOf(i),value); > } > > V get(int i) { > super.get(Integer.valueOf(i)); > } > } > > then Wicket can do the same as it did earlier but with 1000 less lines of > code. > Perhaps those 1000 lines could be used on some other amazing feature. > > Br, > Tuomas > > Quoting Igor Vaynberg <[email protected]>: > >> this is borderline nitpicking. just because it is coded the way you >> wouldnt doesnt mean we have to change it. >> >> -igor >> >> On Fri, Feb 13, 2009 at 12:23 PM, Antony Stubbs <[email protected]> >> wrote: >>> >>> Are we also not allowed to debate the merits of existing functionality? >>> >>> On 13/02/2009, at 7:46 PM, Igor Vaynberg wrote: >>> >>>> why are we even talking about it. nothing is broken in wicket, >>>> correct? you are not forced to use it in your code. we like it. it >>>> does not impact you. where is the problem? >>>> >>>> -igor >>>> >>>> On Fri, Feb 13, 2009 at 11:32 AM, Johan Compagner <[email protected]> >>>> wrote: >>>>> >>>>> 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 >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>>> >>>>> >>> >>> >> > > > -- Become a Wicket expert, learn from the best: http://wicketinaction.com Apache Wicket 1.3.5 is released Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3.
