Tom, > I know I also came in late into this thread. I would like to say I am very > excited about the possibilities of FOP in the future and the already > realized gains FOP gives. My overall grasp of FOP at this moment is still > limited but I have been delving into the code and using it for a current > project for the past 2 months. In no way am I trying to be insulting to > anyone. I realize everyone here is very well versed in various areas of > programming. Performance has always been an interest to me in general so I > enjoy these types of topics. I don't mind being proven wrong. > > Yes. You are correct on your assumptions based on your code. > > Maybe I should have been more clear and read the initial beginning to this > thread but I would like to clear two points up, my apologies. > > I was trying to refer to two seperate issues that were being discussed, > more so to what happens during runtime then compile time. > > The first point was what the String and StringBuffer java code looks in the > pcode. String does do concantenation with the concat method and > StringBuffer with append?. > > It does do that except under certain conditions. > > So, what are the conditions under the + operator? > > -If there is a chain of anonymous strings being initialized to a variable a > LOAD happens. > -If there is 1 reference to a String at the head or end of a chain of > anonymous Strings a String.concat happens > -If there are only 2 references to a String(s) being "concantenated using + > operator" a String.concat happens > -If the chain contains 2 or more anonymous strings seperated by at least 1 > reference to a String StringBuffer.append happens > -If the chain contains 3 or more references to a String(s) > StringBuffer.append happens > -If the chain contains at least 2 references to a String(s) and at least 1 > anonymous String StringBuffer.append happens > > What are the conditions for += operator? > > -They are the same as above except for the additional concantenation that > happens implicitly to the variable adding to itself.
> So to the statement that StringBuffer.append happens in "String addition" > is only partly true given String.concat happens in a subset of the cases. Great stuff. I hadn't done tests with two Strings and I think that the scenarios you provide us with are great. <snip /> When I looked at the generated pcode I couldn't understand why there where so many (any) valueOf operations, so I regenerated the code using 1.4.1, and guess what ... it's very different. Sun have made some considerable leeps forward in String handling. Method void concatTests() 0 ldc #12 <String "foo"> 2 astore_1 3 new #2 <Class java.lang.StringBuffer> 6 dup 7 invokespecial #3 <Method java.lang.StringBuffer()> 10 aload_1 11 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 14 ldc #13 <String "bar"> 16 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 19 invokevirtual #10 <Method java.lang.String toString()> 22 astore_1 23 ldc #14 <String "sofarsogood"> 25 astore_2 26 new #2 <Class java.lang.StringBuffer> 29 dup 30 invokespecial #3 <Method java.lang.StringBuffer()> 33 ldc #15 <String "boofar"> 35 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 38 aload_1 39 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 42 invokevirtual #10 <Method java.lang.String toString()> 45 astore_3 46 new #2 <Class java.lang.StringBuffer> 49 dup 50 invokespecial #3 <Method java.lang.StringBuffer()> 53 aload_2 54 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 57 aload_3 58 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 61 invokevirtual #10 <Method java.lang.String toString()> 64 astore 4 66 new #2 <Class java.lang.StringBuffer> 69 dup 70 invokespecial #3 <Method java.lang.StringBuffer()> 73 aload_1 74 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 77 aload_2 78 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 81 aload_3 82 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 85 invokevirtual #10 <Method java.lang.String toString()> 88 astore 5 90 new #2 <Class java.lang.StringBuffer> 93 dup 94 invokespecial #3 <Method java.lang.StringBuffer()> 97 aload_0 98 ldc #16 <String "goo"> 100 invokespecial #7 <Method java.lang.String makeString(java.lang.String)> 103 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 106 aload_0 107 ldc #13 <String "bar"> 109 invokespecial #7 <Method java.lang.String makeString(java.lang.String)> 112 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 115 invokevirtual #10 <Method java.lang.String toString()> 118 astore 6 120 new #2 <Class java.lang.StringBuffer> 123 dup 124 invokespecial #3 <Method java.lang.StringBuffer()> 127 ldc #17 <String "boo"> 129 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 132 aload_1 133 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 136 ldc #18 <String "far"> 138 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 141 invokevirtual #10 <Method java.lang.String toString()> 144 astore 7 146 new #2 <Class java.lang.StringBuffer> 149 dup 150 invokespecial #3 <Method java.lang.StringBuffer()> 153 aload 4 155 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 158 aload 5 160 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 163 aload 6 165 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 168 invokevirtual #10 <Method java.lang.String toString()> 171 astore 4 173 new #2 <Class java.lang.StringBuffer> 176 dup 177 invokespecial #3 <Method java.lang.StringBuffer()> 180 aload 4 182 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 185 ldc #19 <String "foobarfoo"> 187 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 190 invokevirtual #10 <Method java.lang.String toString()> 193 astore 4 195 new #2 <Class java.lang.StringBuffer> 198 dup 199 invokespecial #3 <Method java.lang.StringBuffer()> 202 aload 4 204 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 207 ldc #20 <String "boobar"> 209 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 212 aload 5 214 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 217 invokevirtual #10 <Method java.lang.String toString()> 220 astore 4 222 new #2 <Class java.lang.StringBuffer> 225 dup 226 invokespecial #3 <Method java.lang.StringBuffer()> 229 aload 4 231 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 234 ldc #17 <String "boo"> 236 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 239 aload 5 241 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 244 ldc #13 <String "bar"> 246 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 249 invokevirtual #10 <Method java.lang.String toString()> 252 astore 4 254 new #2 <Class java.lang.StringBuffer> 257 dup 258 invokespecial #3 <Method java.lang.StringBuffer()> 261 aload_2 262 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 265 aload_2 266 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 269 invokevirtual #10 <Method java.lang.String toString()> 272 astore 8 274 new #2 <Class java.lang.StringBuffer> 277 dup 278 invokespecial #3 <Method java.lang.StringBuffer()> 281 aload_2 282 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 285 aload_3 286 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 289 ldc #21 <String "end"> 291 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)> 294 invokevirtual #10 <Method java.lang.String toString()> 297 astore 9 299 return Which goes further to my argument of leaving it to the compiler. > The point that is more interesting is what happens during runtime and > that's what I was trying to emphasize, poorly. > > The question is how many String objects are being handled by the JVM in > memory, how often garbage collection happens, and at what cost? I have not > timed your examples but I believe what you stated. I have run similar tests > but from a different angle. The only difference between tests was that they > were controlled within a loop. The times were different. The reason I did > this is to see how much memory and time is spent within the scope of each > method. > > The testStringAppendloop was exponentially faster with testStringAddloop > coming in second and third for testStringIncrementloop. The times of course > will differ on different platforms and cpu's but I list them anyway. That's for sure. As I pointed out earlier loops are one of the places you should consider a StringBuffer. > This is my sample code derived from your examples; byte-code following. > 1.4.0_01-b03 > > times with 3000 iterations compaq 512 mb 866ghz intel cpu: > 16 ms testStringAppendloop > 2000 ms testStringAddloop > 5531 ms testStringIncrementloop > > public String testStringIncrementloop(int loop) > { > String temp = ""; > > for (int i=0;i<loop;i++) > { > temp += makeString("this is "); > temp += "a "; > temp += makeString("concat test"); > } > > return temp; > > } > > public String testStringAddloop(int loop) > { > String temp = ""; > > for (int i=0;i<loop;i++) > { > temp = temp + makeString("this is ") + "a " + makeString("concat > test"); > } > > return temp; > } > > public String testStringAppendloop(int loop) > { > StringBuffer temp = new StringBuffer(""); > > for (int i=0;i<loop;i++) > { > temp.append(makeString("this is ")).append("a > ").append(makeString("concat test")); > } > > return temp.toString(); > } You can cut the garbage created by this sort of loop by increasing the buffer allocation when the StringBuffer is initialised. StringBuffers start with a very small buffer (16 bytes) so almost any action will cause them to grow. In many cases you can estimate (with the aid of a couple of quick tests) and allocate an appropriate amount. When I started this thread it was to point out that blanket StringBuffer usage did not always improve performance and in many common cases decreased it. I'm not anti StringBuffer, I use them all the time I wanted to increase the awareness of how Strings work. I think the resulting conversations have certianly done that, that objective has been obtained. The other one (which kinda got forgotten) was to try and encourage people to code in the simplest manor and leave the optimisations (for the most part) until you're running your code through a profiler. That way you'll be able to concetrate your efforts on the real hot stuff. It's all well and good optimising the String access of a routine, but if that routine is only taking 0.001% of your opperation time then you've pretty much wasted your time :). Oh and remember that hotspot will re-write your code on the fly, inlining method calls and such, thus changing the performance characteristics of the I think once the 1.0 archetecture stuff is in place and the code is drives where we concentrate on finding the hot spots and quash them. This will help make fop the best fo processor out there. -k. ps: Sorry if this is boring anyone :(. -- Kevin O'Neill <[EMAIL PROTECTED]> rocketred pty ltd --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]