2

I need to do :

Dictionary cache;
cache = new Hashtable();
this.getDocument().putProperty("imageCache", cache);

Then I have a method who does :

cache.put(url, picture);

Where picture is an Image object. I create this way :

public Image getSmiley(String smileyName) {
    BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
    Graphics g = img.getGraphics();
    ImageIcon myicon = new ImageIcon(getClass().getResource("/ola/smileys/" + smileyName + ".png"));
    myicon.paintIcon(null, g, 0, 0);
    return img;
}

I have run a profiling and I have seen that when I call this method "put", the application slows down incredibly. What could be the reason ?

Thank you very much.

Best Regards

Vincent Roye
  • 2,751
  • 7
  • 33
  • 53

4 Answers4

5

I suspect that this might be due to your using the URL class as the key type.

The javadoc for URL.equals(Object) says this:

Two URL objects are equal if they have the same protocol, reference equivalent hosts, have the same port number on the host, and the same file and fragment of the file.

Two hosts are considered equivalent if both host names can be resolved into the same IP addresses; else if either host name can't be resolved, the host names must be equal without regard to case; or both host names equal to null.

Since hosts comparison requires name resolution, this operation is a blocking operation.

When you use a URL instance as a key in a map, then each time a key is compared to a different one you could be triggering a DNS lookup ... and that could take a long time.


If this is your problem, then you need to change the key type of the map to String or URI ... or something else that doesn't have an expensive equals(Object) method.

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • It will try `hashcode()` first, which is cached in URL class. So I do not think it will casue the application to slow down incredibly. However, it really depends how "incredibly" slow is. – wyz Dec 08 '11 at 04:45
  • Yes ... but if you assume that the instance of `URL` that you have in your hand has not been hashed before, then the `hashcode()` call will entail resolving the hostname. Plus, `equals()` needs to be called if there are hash collisions ... for the current table size. – Stephen C Dec 08 '11 at 05:37
  • I agree with you. The first suspect come across to me is `hashcode()` and `equals()` method of the key class too. But I really doubt if `hashcode()` and `equals()` on a will slow the application "incredibly". – wyz Dec 08 '11 at 05:53
  • It depends on how fast DNS lookup is for the hosts. In my experience, it *can* be slow enough to qualify as an "incredible" slowdown. – Stephen C Dec 08 '11 at 06:18
  • You are right. `handler.equals(this, u2)` will be invoked and it can slow down incredibly. – wyz Dec 08 '11 at 06:26
2

I'm just giving a guess, but I think it might be due to the underlying hash structure having to be resized.

When you're 'put'ing a value into a hashtable, once it reaches a certain capacity, it has to expand the underlying array -- otherwise, you end up getting a lot of hash collisions. However, this array expansion operation is expensive -- it has to allocate space for the new array and copy values into the new array.

One suggestion would be to give a reasonable initial capacity to the Hashtable constructor.

1

How much is "incredibly"?

I can't guarantee how much of an improvement it would make, but try using HashMap instead of Hashtable. HashMap is not synchronized, which I'm guessing you don't need here, since everything should be done on a single thread for your UI anyway.

See Differences between HashMap and Hashtable? for some additional details of the differences between these.

Community
  • 1
  • 1
ziesemer
  • 27,712
  • 8
  • 86
  • 94
  • 2
    That is sound advice, but should not make any noticeable performance different, let alone something "incredible". – Thilo Dec 08 '11 at 04:33
  • 1
    Thilo - agreed. +1 for Nick's answer about providing an initial capacity to the map. – ziesemer Dec 08 '11 at 04:38
0

I assume you're trying to pre-load a cache so you can do something like showing local images in a JEditorPane.

I just had this problem & Stephen C correctly identified the issue.

Originally I was using urls which started with http://, I switched to urls starting with file:/ and it fixed the problem.

These urls are never actually connected to, they're just unique keys for the hash so just making sure the URL object knows it doesn't need a DNS lookup to resolve them is enough, & changing to the file protocol does that.

Jonathan
  • 1,327
  • 3
  • 15
  • 24