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














Reply via email to