Skip to Content

Hi all,

This is kind of a reply to this The First Law of Optimization entry by Valery,Silaev, who obviously likes to read my blog. I also would like to explain im more detail, why I think knowing the String api is pretty important.

“Empty String in JVM occupies 40 bytes in memory? Wow, that’s cool to know!”

Sure this is important to know. My experience is that a lot of developers, do not know what the overhead of String is. This is not just a feeling, but it’s supported by a lot of data taken from heap dumps and of course by speaking to the developers.

This has nothing to do with premature optimization, which as we all know, who read Knut every evening as a bedtime stories for our childs “is the root of all evil (or at least most of it) in programming.”

It’s about getting the basic things right, and fact is that the class String tends to be overused and pretty often is used incorrectly .

“The Expensive Compiler Story”

Of course I’m aware, that there are certain situations, in which the compiler optimizes away the overhead of “+”, and I was simplifying because I didn’t want to create a big blog entry with 154 lines.

But honestly, if you tell the developer to use StringBuffer on JDK 1.4 and StringBuilder on JDK 1.5, and the developer has to maintain code for both JDK. What do you think most developers will do ? I guess they will just go ahead with StringBuffer, at least in code that is unlikely to be performance critical. As a matter of fact, on an recent JVM, uncontented synchronization is almost always practically zero.

Telling a developer,”just test everything by yourself”, isn’t really practical nor efficient, because it’s just duplicated work. Of course you want to profile/measure your complete application, to be sure that you don’t have any unexpected bottlenecks.

“String.intern()”

It Is String.intern() good or evil ?, String.intern() should rather not be used, at least on SUN VM’s up to JDK 1.5. But maybe a JVM of a large software company in Walldorf, will improve the situation within the near future 😉 By the way using “StringA == StringB” rather than “StringA.equals(StringB)” will usually not make a difference, because the first statement in String.equals does “StringA == StringB” anyway.

“Reflection”

Yes reflection performance improved a lot on most VM’s. I’m not sure whether it’s fast on all VM’s. One problem with reflection at least on SUN VM’s is that classes are generated on the fly, which occupy permspace. Ever wondered about messages like this in your std_server0.out ?

[Unloading class sun.reflect.GeneratedSerializationConstructorAccessor51] [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor143] [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor93] [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor211] [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor207] [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor47]

These messages are caused by the unloading (due to a Full GC), of the automatically generated classes for reflection. As far as I remember there was a problem with a non SUN VM, where this would cause very long GC pauses (minutes), because the VM was not optimized for this kind of stuff. And also reflection got pretty fast in the meantime, it can still be infinitely slower than a simple call, because it defeats inlining.

“Do not optimize object construction”

I do not fully agree with this statement. If this means don’t care about how much objects you created, then I disagree. Sure object creation in Java is freaking fast, almost always faster than a malloc in C and the clean up through the minor GC is very efficient. But the problem is that you must be carefull about how long your objects live, because if they live to long they will go to old space and can only be reclaimed by a full GC, which is costly.

Predicting how long an object lives can be very difficult in an complex J2EE enviroment. It also doesn’t make much sense to create lot’s of duplicates of objects which are really constants. More about this in later blog. For more information about Garbage Collection in Java (1.4) check this link

@Valery,Silaev. I like to read your blog too 🙂 In fact I agree in principle with most of your statements.

Regards,
Markus

To report this post you need to login first.

6 Comments

You must be Logged on to comment or reply to a post.

  1. Richard Birenheide
    There is another issue with reflection one should not underestimate: It can dramatically add to the mainentance and bug finding cost. First of all, why do we use a typed language with all its overhead? To have things fail early. Even worse, you can gain access to stuff which you can see at runtime but won’t see at designtime for good reasons (at least in a multicomponent environment). When would such an access fail, if the referenced class changes unattended (and no tool will tell you in advance)? Right, at runtime. So I’d judge still valid what Bloch says in chapter 7.7. of Effective Java…

    Regards
    Richard

    (0) 
  2. Valery Silaev
    Markus,

    Unfortunatelly, you totally miss the point of my post.
    1. String size
    Ok, let us agree that String object has size in memory. Anyway, it will be surprising otherwise 😉 And what? Your 3 posts (parts 1, 2, 4) do not show techniques to minimize String usage. What is your message? Use char[] instead because you save 40 bytes? Do you know the price in productivity in such change? No substrings, no RegExps, custom functions to search character by index…
    2. StringBuffer.
    Now I wonder do you have expirience with optimizing this problem? See, subsequent String concatenations are grouped, i.e “CONST1” + varX + “CONST2” is a concatenation using one StringBuffer. But concatenations in separate expressions force creation of new StringBuffer per expression:
    /* First StringBuffer is created and used here */
    String x = “CONST1” + varX + “CONST2”;
    /* Second StringBuffer is created here */
    x += “ANYTHING_ELSE”;
    So it would be not so hard to provide real example if you ever faced it in reality 😉
    By the way, even second case _may_ be optimized by compiler — it can keep track of String concatenations and String assignments and create StringBuffer-s only when necessary. Unfortunately, current Java compilers are the most dumb compilers 🙁 Hope that SAP JVM team pay attention to this — it’s not that complex task to optimize String concatenations within single method at compiler level.
    3. String.intern()
    Yes, here we totally agree about String.intern() gotchas. However, the point was the fact of pre-mature optimization itself, not the mechanism used.
    4. Reflection
    Yes, I know the cost of reflection. And I pointed out that it never be the same as cost of direct call. But, again, the point was different: even such thing may be non-critical in overall application. So instead of optimizing reflection you may concentrate on business/technology problem you are solving. And fix reflection afterwards if it hurts.

    VS

    (0) 
    1. Valery Silaev
      When I said SAP JVM, I mean SAP JDK.
      Actually, I don’t know whether or not SAP created own JDK (run-time + tools like compiler) or only run-time (i.e. JRE)

      VS

      (0) 
      1. Markus Kohler Post author
        Hi,
        To my knowledge SAP has complete control over the runtime and the tools. To my knowledge the compiler was left as it is so far.

        I also tend to use sometimes  the term “SUN JVM”, when I mean SUN or SAP JVM, because the VM’s are very similiar.

        Regards,
        Markus

        (0) 
      2. Markus Kohler Post author
        Hi,
        To my knowledge SAP has complete control over the runtime and the tools. To my knowledge the compiler was left as it is so far.

        I also tend to use sometimes  the term “SUN JVM”, when I mean SUN or SAP JVM, because the VM’s are very similiar.

        Regards,
        Markus

        (0) 
    2. Markus Kohler Post author
      Hi,
      The message is
      – Beware that the usage of Strings can be costly.
      – Beware of how String/StringBuffer works
      – Avoid copying Strings, and especially the internal char[]
      – Consider using integers or longs

      The point of the example was not to show the best way to do this concatenations. It was to there to show a real world example, how these String and StringBuffer functions are often used.

      Regards,
      Markus

      (0) 

Leave a Reply