• (cs)

    PROTIP: if you're trying to fix performance problems by caching integers, you're Doing It Wrong(tm).

    ...

    Screw that... if you're caching integers in any scenario, you're doing it so wrong you should probably shouldn't have tried to be a programmer in the first place.

    Also, FRIST.

  • anonym (unregistered)

    if ParentID == MathUtil.getInteger(0) first

  • (cs)

    Reimplementing standard library functionality. Yawn.

    http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#valueOf%28int%29

    Returns a Integer instance representing the specified int value. [If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

  • SR (unregistered)

    StringUtil.getString("G"); StringUtil.getString("o"); StringUtil.getString("o"); StringUtil.getString("d"); StringUtil.getString(" "); StringUtil.getString("G"); StringUtil.getString("r"); StringUtil.getString("i"); StringUtil.getString("e"); StringUtil.getString("f"); StringUtil.getString("!"); StringUtil.getString(" "); StringUtil.getString("W"); StringUtil.getString("h"); StringUtil.getString("a"); StringUtil.getString("t"); StringUtil.getString(" "); StringUtil.getString("a"); StringUtil.getString(" "); StringUtil.getString("M"); StringUtil.getString("u"); StringUtil.getString("p"); StringUtil.getString("p"); StringUtil.getString("e"); StringUtil.getString("t"); StringUtil.getString("!");

  • Crash Magnet (unregistered)

    And my nomination for best WTF since "Paula Beans".

  • F (unregistered) in reply to jspenguin
    jspenguin:
    Reimplementing standard library functionality. Yawn.

    http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#valueOf%28int%29

    Returns a Integer instance representing the specified int value. [If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

    OTOH, maybe you don't need to encapsulate the value in an Integer object in the first place, and a primitive would do the job.

  • (cs)

    Ok, so this is stupid but maybe not as stupid as it first seems... He is not caching ints, he's caching the Integer object representation of an int. If he was regularly using loads of Integer objects for values below 256, this might save some memory. As the latest GC implementations optimise towards short lived objects though, I doubt there would be any significant gain, and all for the sake of some horrible code. And I hope he has a good reason for not just using an int as the ParentId - or is Java's nullable int implementation really that bad? (seems like he's using the magic number 0 for null anyway)

  • (cs) in reply to jspenguin
    jspenguin:
    Reimplementing standard library functionality. Yawn.

    http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#valueOf%28int%29

    Returns a Integer instance representing the specified int value. [If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

    It's barely possible that the original coder actually anticipated standard library functionality, since that feature didn't arrive in Java until 1.5.

    (Sadly, when I'm required to write Java, I have to ensure the result works under 1.4, because some customers won't update their Java installs beyond that point. Java 7? Hah!)

  • LordOfThePigs (unregistered)

    Well, the principle is not that stupid at all since this is already what the JRE does. The Java specification requires the instances of the Integer class representing integer numbers between -128 to 127 to be cached. Also in java,

    Integer customerId = 0;

    compiles in bytecode to

    Integer customerId = Integer.valueOf(0);

    which returns the cached instance of 0. This avoids a lot of garbage collection, and can save a significant amount of memory, since the minimal memory size of an object in java is 2 pointers (so 8 or 16 bytes depending on your platform) + the size of whatever members it contains. And I'm sure we can all agree that spending 20 bytes when we should really only use 4 is stupid, especially if you do it with 5'000 different instances of the same immutable Integer object.

    Now what is stupid is that the libraries already do it for you, but as the comments show, many people don't know that...

  • (cs) in reply to jspenguin
    jspenguin:
    Reimplementing standard library functionality. Yawn.

    http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#valueOf%28int%29

    Returns a Integer instance representing the specified int value. [If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

    That's what I thought too. If caching small Integers is a WTF then the post should be about Sun's API implementation rather than some random guy working for an unspecified company.

    -- Submission attempt 3

  • LordOfThePigs (unregistered) in reply to SR

    You might want to look at String.intern() before you post further comments...

  • LordOfThePigs (unregistered) in reply to SR
    SR:
    StringUtil.getString("G"); StringUtil.getString("o"); StringUtil.getString("o"); StringUtil.getString("d"); StringUtil.getString(" "); StringUtil.getString("G"); StringUtil.getString("r"); StringUtil.getString("i"); StringUtil.getString("e"); StringUtil.getString("f"); StringUtil.getString("!"); StringUtil.getString(" "); StringUtil.getString("W"); StringUtil.getString("h"); StringUtil.getString("a"); StringUtil.getString("t"); StringUtil.getString(" "); StringUtil.getString("a"); StringUtil.getString(" "); StringUtil.getString("M"); StringUtil.getString("u"); StringUtil.getString("p"); StringUtil.getString("p"); StringUtil.getString("e"); StringUtil.getString("t"); StringUtil.getString("!");

    Damn, the previous post refers to the one quoted above...

  • (cs) in reply to Bellinghman
    Bellinghman:
    It's barely possible that the original coder actually anticipated standard library functionality, since that feature didn't arrive in Java until 1.5.
    Nor did auto-boxing, which means that the post's observation
    The original post:
    seemed like an overly complex way of writing "ParentID = 0;"

    would be nonsense. Of course, given the general level of proof-reading that seems to go into posts here...

  • c0rnh0li0 (unregistered)

    'MathUtil.getInteger(...)' needs to be rewritten for the enterprise:

    public static Integer getInteger(final int i) {
      try {
        return arrCachedIntegers[i];
      } catch(ArrayIndexOutOfBoundsException e) {
        return new Integer(i);
      }
    }
    
  • mr_smith (unregistered) in reply to LordOfThePigs
    LordOfThePigs:
    Well, the principle is not that stupid at all since this is already what the JRE does. The Java specification requires the instances of the Integer class representing integer numbers between -128 to 127 to be cached. Also in java,

    Integer customerId = 0;

    compiles in bytecode to

    Integer customerId = Integer.valueOf(0);

    which returns the cached instance of 0. This avoids a lot of garbage collection, and can save a significant amount of memory, since the minimal memory size of an object in java is 2 pointers (so 8 or 16 bytes depending on your platform) + the size of whatever members it contains. And I'm sure we can all agree that spending 20 bytes when we should really only use 4 is stupid, especially if you do it with 5'000 different instances of the same immutable Integer object.

    Now what is stupid is that the libraries already do it for you, but as the comments show, many people don't know that...

    The worst thing about the daily wtf is that there is a whole group of wtf makers hanging around trying to pretend they are good developers. I see this as the "actively pick on somebody else so they won't notice me" strategy.

  • Procedural (unregistered)

    Minor quibble, but it is "hare brain". Nervous small brain, mostly concerned with sex and eating, not a great strategist. That`s why it is so often opposed to the fox in stories.

  • grzlbrmft (unregistered)

    Well, if you have some boiling water left, put it in the freezer, in case you need it later!

    (I know that's not a new one, but it came to my mind when I saw that WTF)

  • Schobi (unregistered) in reply to Bellinghman
    Bellinghman:
    [...] (Sadly, when I'm required to write Java, I have to ensure the result works under 1.4, because some customers won't update their Java installs beyond that point. Java 7? Hah!)

    Wait a minute! There exists a version 7 of Java? That must be joke, right? I mean, everybody knows that Java versions go up to 6 but not beyond.

  • Philipp (unregistered) in reply to Bellinghman

    @Bellinghman

    Might be interesting for customers:

    http://java.sun.com/j2se/1.4.2/

    J2SE 1.4.2 is in its Java Technology End of Life (EOL) transition period. The EOL transition period began Dec, 11 2006 and will complete October 30th, 2008, when J2SE 1.4.2 will have reached its End of Service Life (EOSL).
  • tego (unregistered) in reply to Schobi
    Schobi:
    Bellinghman:
    [...] (Sadly, when I'm required to write Java, I have to ensure the result works under 1.4, because some customers won't update their Java installs beyond that point. Java 7? Hah!)

    Wait a minute! There exists a version 7 of Java? That must be joke, right? I mean, everybody knows that Java versions go up to 6 but not beyond.

    this one goes to SEVEN!

  • Calling Out Hypocrites (unregistered) in reply to mr_smith
    mr_smith:
    The worst thing about the daily wtf is that there is a whole group of wtf makers hanging around trying to pretend they are good developers. I see this as the "actively pick on somebody else so they won't notice me" strategy.

    mr_smith, you forgot to submit your code with your post.

  • Vlad Patryshev (unregistered)

    Looks suspiciously familiar. I saw this kind of cache pretty recently. Not that it is being used these days of enlightenment, but the cache is still there, by the principle that that that is is right.

  • (cs) in reply to Philipp
    Philipp:
    @Bellinghman

    Might be interesting for customers:

    http://java.sun.com/j2se/1.4.2/

    J2SE 1.4.2 is in its Java Technology End of Life (EOL) transition period. The EOL transition period began Dec, 11 2006 and will complete October 30th, 2008, when J2SE 1.4.2 will have reached its End of Service Life (EOSL).
    Aye. And don't mention Windows 200 either, please.
  • (cs) in reply to pjt33
    pjt33:
    Nor did auto-boxing, which means that the post's observation
    The original post:
    seemed like an overly complex way of writing "ParentID = 0;"
    would be nonsense. Of course, given the general level of proof-reading that seems to go into posts here...
    Ah, good point.

    (My brain saw that, and momentarily flipped into C++ mode, reading the "= 0" as "= null". Bad brain. No caffeine for you.)

    I suppose it's vaguely conceivable that the Integer caching was added in a pre-1.5 version, and that when auto-boxing arrived with 1.5, that facility was gratefully received, but the internal caching wasn't noticed.

    I do wonder whether the coder had ever measured whether the generation of lots of Integer objects caused any problems in the first place.

  • Vlad Patryshev (unregistered) in reply to F

    Primitives don't work as keys; and not every jvm is 1.5 compatible; if you try RIMM, you'll be amazed how careful one should be allocating Integers or even using String literals.

  • Jamie (unregistered)

    The maze of twisy passages was from Zork's predecessor the original and the best Collosal Cave Adventure. I once wrote a port of Collosal Cave Adventure for a bizzare programming language as part of a research project :)

  • (cs) in reply to Crash Magnet
    Crash Magnet:
    And my nomination for best WTF since "Paula Beans".
    +1
  • Patrick (unregistered)

    Who even does

    new Integer(0)
    anyway? That line in itself is a WTF.

  • SR (unregistered) in reply to LordOfThePigs
    LordOfThePigs:
    You might want to look at String.intern() before you post further comments...

    And you might want to refer to Psuedocode.

  • ClutchDude (unregistered) in reply to Bellinghman
    Bellinghman:
    (Sadly, when I'm required to write Java, I have to ensure the result works under 1.4, because some customers won't update their Java installs beyond that point. Java 7? Hah!)

    You too?!?!?!?

    Our codebase has been 1.4.2 since the project's inception.

    Thankfully, we're moving to 1.6 before too long. The code is migrated and regression testing needs to be done.

    Convenience for-loops, autoboxing, and generic support for all(And more stuff since 1.5)!

  • Ben (unregistered)

    You've made an eggcorn. It's "hare brained", not "hair brained". As in hare, an animal.

  • (cs)

    What an idiot! Rather than pre-cache integers 0-255 in the constructor, he should use the array to store the 256 most used integers!

    The constructor would simply mark all elements of the array as unused (why not use an array of boolean values for such a purpose?).

    Then, when a function requests an integer, iterate through the array, and when the integer of required value is found, return it. If it isn't found, iterate through the array to find an unused slot, and cache the new integer there.

    If the array is full, why not re-allocate it as a bigger array? Then you can cache every integer you ever use!

    You could even log every integer access to a file, and analyse the results to optimise integer usage; why use 6 when 5 is near enough and is already being used by another function?!

    In fact, it could analyse the logs itself and identify the most used integers, then parse its own source code to find integers that are "near enough" and change them, recompile itself, launch a new instance and quit. That way it is SELF OPTIMISING!

  • (cs) in reply to Xeron

    Oh... but then, you could store every integer in an SQL table, then retrieve it before calling getInteger() on the result. That way, the program only has to modify the SQL table like this:

    UPDATE Integers SET Value=5 WHERE Actual=6

    then you wouldn't need to recompile the app; it automatically uses "near enough" values straight away!

  • (cs) in reply to Bellinghman
    Bellinghman:
    I do wonder whether the coder had ever measured whether the generation of lots of Integer objects caused any problems in the first place.
    I've got code where it is a big win when processing can generate lots of immutable objects (not in Java as it happens, but it's an equivalent principle). Basically, you're using the Flyweight pattern with highly-sharable objects, and if you're managing to get a good amount of sharing of references going, that's a delicious win. In fact, it turned out to be such a big win when we deployed that code in practice that it was enabled even for cases where it was not a big win (the cost of the cache building was surprisingly small, the poor-performance cases unlikely).
  • Jones (unregistered) in reply to Bellinghman
    Bellinghman:
    jspenguin:
    Reimplementing standard library functionality. Yawn.

    http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#valueOf%28int%29 ...

    It's barely possible that the original coder actually anticipated standard library functionality, since that feature didn't arrive in Java until 1.5.

    The caching is much older than 1.5. Only that specific method is not.

  • (cs)

    Xeron wins the thread. \o/

  • Bavo (unregistered)

    AFAIK integers below 256 are always cached automatically which makes

    Integer a = new Integer(3); Integer b = new Integer(3); assert a==b;

    succeed, because they will always poijt to the same instance. Typical JCJP gotcha :)

    Integer a = new Integer(300); Integer b = new Integer(300); assert a==b;

    but this will not.

  • Daniel Pitts (unregistered) in reply to Bellinghman

    Bellinghman:

    Sadly, when I'm required to write Java, I have to ensure the result works under 1.4, because some customers won't update their Java installs beyond that point. Java 7? Hah!
    That is very sad. Even Java 1.5 is end of life. You should tell your customers that there are significant performance and security improvements in Java 1.6. You wouldn't be lying, even though your motivation would be the ability to use an improved language.
  • fbomb (unregistered)

    In a fit of pedantry, I feel obligated to point out that "maze of twisty passages, all alike" is from Adventure. Not Zork.

  • aristos_achaion (unregistered) in reply to F
    F:
    jspenguin:
    Reimplementing standard library functionality. Yawn.

    http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#valueOf%28int%29

    Returns a Integer instance representing the specified int value. [If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

    OTOH, maybe you don't need to encapsulate the value in an Integer object in the first place, and a primitive would do the job.

    You seem to underestimate the utility of having an Integer object, especially if you're dealing with generics.

    Also, while valueOf caches too, remember that valueOf caches frequently used values, which presumably means that a number greater than 256 could get cached and unused numbers less than 256 wouldn't be. He's decided to limit "caching" to numbers less than 256, I guess because otherwise it'd be a self-defeating memory hog. So there's a pre-built integer for 17 and 31, but not one for 512 and 1024. That's why this is a WTF, not just a reimplemented library function.

  • Chris (unregistered) in reply to Bavo

    Uhhh... no, both object comparisons will fail because you explictly created new objects. If you create the Integers using autoboxing or Integer.valueOf() then what you say has some merit however.

    Note though that the actual default range that is cached is -128 to 127. In more recent JDKs you can override the upper limit by setting the java.lang.Integer.IntegerCache.high system property.

    There are more WTFs in these comments than the original post - in fact the original code is a valid solution to a (possibly) valid problem. We have similar caches and object pools in our codebase where we need them. In some cases the performance boost is huge.

  • David (unregistered)

    So are we saying that the Real WTF is Java itself?

  • (cs)

    Writing performance critical code in Java is stupid.

  • Prof (unregistered)
    ParentID = MathUtil.getInteger(0)
    But even that is wrong, because there's still a hard-coded integer in your source, and hard-coded programs are inflexible. Besides, who knows what the zero (or other constant) represents? It isn't documented! How did you arrive at that value?

    No, a Good Programmer (TM) never uses any constants.

    You have to bootstrap a few things like this, but after that it is easy:

    # create a zero by clearing out any debris that may have been in memory
    Z = Z - Z
    # create a one (true)
    I = (Z == Z)
    # two
    T = I + I
    # and so on...
    
  • Chris (unregistered) in reply to frits
    frits:
    Writing performance critical code in Java is stupid.

    Sigh... this persistent myth is simply not true for the most part anymore. We write server software at an investment bank that processes huge volumes of data and is very performance critical. Well written Java is more than up to the task for what we do. Bottlenecks invariably are due to IO or algorithm design, not the choice of Java vs say C or C++.

    http://blogs.azulsystems.com/cliff/2009/09/java-vs-c-performance-again.html

  • (cs) in reply to Chris

    I dare you to write your database engine in pure Java.

  • Chris (unregistered) in reply to frits
    frits:
    I dare you to write your database engine in pure Java.

    What, like one of these?

    http://java-source.net/open-source/database-engines

  • DAT (unregistered)

    By the way, the idiom is "hare-brained," not "hair-brained." It goes along with the one about "mad as March hare."

  • Hugh (unregistered) in reply to Jones
    Jones:
    Bellinghman:
    jspenguin:
    Reimplementing standard library functionality. Yawn.

    http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#valueOf%28int%29 ...

    It's barely possible that the original coder actually anticipated standard library functionality, since that feature didn't arrive in Java until 1.5.

    The caching is much older than 1.5. Only that specific method is not.

    Please excuse the typo on 'hair-brained'.

    The portal was built using Java 6. Everyone that I've spoken with who knows the history of the project is glad that the lead developer who built it is no longer with the company. The Integer Cache was just one example of the coding disasters that I ran across.

    Here are some additional highlights.

    Every URL on the portal is the same no matter what page you go to. Most pages are derived from information in classes that are cached in the user's session. OK, they didn't want the user bookmarking pages or something like that. Unfortunately, they didn't take into account the fact that a user might hit the browser's back button. So, when you go back and select something else, the session's objects aren't current and it throws lots of errors. It also had the interesting feature of updating the session objects and refreshing the entire page whenever a user selected an item from a picklist.

    There was another page that displayed up to 10 tables of results in alternating colors. For some reason, they decided to create 10 sets of variables like table1, table2, table3, etc. to put the yellow table data in and another 10 sets like table21, table22, table23, etc. to put the green items in. The data was stored such that if table1 had data, table21 would not. So that if you had 10 tables displayed, the data would be stored like this:

    1. table1
    2.          table22
    3. table3
    4.          table24
    5. table5
    6.          table26
    7. table7
    8.          table28
    9. table9
    10.         table210
    

    There was a lot of code dedicated to storing and then trying to figure out which variables had the table data that they were processing. There were additional variables that were tracking which tableX and table2X variables had data in them rather than examining the tables.

    I managed to reduce the 10,000 line class file with over 300 variables of the form var, var2, var3, entry, entry2, entry3, etc. Note that the first one was not named var1 as you would expect. This added an extra level of fun while trying to reorganize the variables. After putting 30 sets of variables into similarly named lists, the class was reduced to a more manageable 2000 lines. Still bloated but, you could now get a sense of what it was supposed to be doing. Most of the variables also had public getters and setters that are accessed from the JSF pages that they built this in. I ended up putting 1000 lines of variables along with their getters and setters in a separate class so that I could find the main business methods in the class.

    The 2500 line method was nothing more that a pair of nested loops that reduced to less than 100 lines of code. The method originally looked like this:

    if(var...){
    	if(var2 != null && !var2.equals("")){
    		if(entry == ...){
    			50 lines of code...
    		}
    		else{
    			Same 50 lines with one line changed
    		}
    	}
    	if(var3 != null && !var3.equals("")){
    		if(entry == ...){
    			50 lines of code...
    		}
    		else{
    			Same 50 lines with one line changed
    		}
    	}
    	...
    	if(var10 != null && !var10.equals("")){
    	...
    	}
    }
    else if(var2...){
    	if(var != null && !var.equals("")){
    		if(entry == ...){
    			50 lines of code...
    		}
    		else{
    			Same 50 lines with one line changed
    		}
    	}
    	if(var3 != null && !var3.equals("")){
    	...
    	}
    	...
    	if(var10 != null && !var10.equals("")){
    	...
    	}
    }
    else if(var3...){
    	...
    }
    ...
    else if(var10...){
    }
    

    Another odd trait was the unnecessary copy and pasting that was going on. I have found numerous examples like the one above where large blocks of code were wrapped in an if statement and copied into the else statement with only one line changed.

    Oh, I almost forgot. The database also contained a number of parent tables that were referenced throughout the code with a specific numbering scheme. But, when you want to create a link between two tables, the data was stored using a different numbering scheme. Of course, the data was stored as numbers in the database so that it isn't readable and this feature isn't documented in the code. Those numbers were in a separate helper table in the database. The trick is that only four of the tables have different storage numbers from their application counterparts which meant that I literally had to stumble across it when I was testing saves to one of those four tables.

    Again, these are just the highlights. There are more.

  • PK (unregistered)

    H2 database was written in Java and its way faster than PostgreSQL which was written in C or MySQL which was written in C++.

    Databases are probably the best example of the system, where "performance of the language" does not count. What counts is algorithms. In databases world probably more than anywhere else. It is more likely to get better/more advanced algorithms writing in some high-level language than using plain old C.

Leave a comment on “The Integer Cache”

Log In or post as a guest

Replying to comment #:

« Return to Article