Java Performance Tuning, 2nd Ed.
Every developer has written a microbenchmark (a bit of code that does something 100-1000 times in a tight loop and measure the time it takes for the supposed "expensive operation") to try and prove an argument about which way is "more efficient" based on the execution time. The problem, is when running in a dynamic, managed environment like the 1.4.x JVM, there are more factors that you don't control than ones that you do, and it can be difficult to say whether one piece of code will be "more efficient" than another without testing with actual usage patterns. The second edition of Review of Java Performance Tuning provides substantial benchmarks (not just simple microbenchmarks) with thorough coverage of the JDK including loops, exceptions, strings, threading, and even underlying JVM improvements in the 1.4 VM. This book is one of a kind in its scope and completeness.
The Gory Details
The best part of this book is that it not only tells you how fast various standard Java operations are (sorting strings, dealing with exceptions, etc.), but he has kept all of the timing information from the previous edition of the book. This shows you how the VMs performance has changed from version 1.1.8 up to 1.4.0, and it's very clear that things are getting better. The author also breaks out the timing information for 3 different flavors of the 1.4.0 JVM: mixed interpreted/compiled mode (standard), server (with Hotspot), and interpreted mode only (no run time optimization applied).
Part 1 : Lies, Damn Lies and Statistics
The book starts off with three chapters of sage advice about the tools and process of profiling/tuning. Before you spend any time profiling, you have to have a process and a goal. Without setting goals, the tuning process will never end and it will likely never be successful.
The author outlines a general strategy that will give you a great starting point for your tuning task forces. Chapter 2 presents the profiling facilities that are available in the Java VM and how to interpret the results, while chapter 3 covers VM optimizations (different garbage collectors, memory allocation options) and compiler optimizations.
Part 2 : The Basics
Chapters 4-9 cover the nuts and bolts, code-level optimizations that you can implement. Chapter 4 discusses various object allocation tweaks including: lazy initialization, canonicalizing objects, and how to use the different types of references (Phantom, Soft, and Weak) to implement priority object pooling. Chapter 5 tells you more about handling Strings in Java that you ever wanted to know. Converting numbers (floats, decimals, etc) to Strings efficiently, string matching -- it's all here in gory detail with timings and sample code.
This chapter also shows the author's depth and maturity; when presenting his algorithm to convert integers to Strings, he notes that while his implementation previously beat the pants off of Sun's implementation, in 1.3.1/1.4.0 Sun implemented a change that now beats his code. He analyzes the new implementation, discusses why it's faster without losing face. That is just one of many gems in this updated edition of the book. Chapter 6 covers the cost of throwing and catching exceptions, passing parameters to methods and accessing variables of different scopes (instance vs. local) and different types (scalar vs. array). Chapter 7 covers loop optimization with a java bent. The author offers proof that an exception terminated loop, while bad programming style, can offer better performance than more accepted practices.
Chapter 8 covers IO, focusing in on using the proper flavor of java.io class (stream vs. reader, buffered vs. unbuffered) to achieve the best performance for a given situation. The author also covers performance issues with object serialization (used under the hood in most Java distributed computing mechanisms) in detail and wraps up the chapter with a 12 page discussion of how best to use the "new IO" package (java.nio) that was introduced with Java 1.4. Sadly, the author doesn't offer a detailed timing comparison of the 1.4 NIO API to the existing IO API. Chapter 9 covers Java's native sorting implementations and how to extend their framework for your specific application.
PART 3 : Threads, Distributed Computing and Other Topics
Chapters 10-14 covers a grab bag of topics, including threading, proper Collections use, distributed computing paradigms, and an optimization primer that covers full life cycle approaches to optimization. Chapter 10 does a great job of presenting threading, common threading pitfalls (deadlocks, race conditions), and how to solve them for optimal performance (e.g. proper scope of locks, etc).
Chapter 11 provides a wonderful discussion about one of the most powerful parts of the JDK, the Collections API. It includes detailed timings of using ArrayList vs. LinkedList when traversing and building collections. To close the chapter, the author discusses different object caching implementations and their individual performance results.
Chapter 12 gives some general optimization principles (with code samples) for speeding up distributed computing including techniques to minimize the amount of data transferred along with some more practical advice for designing web services and using JDBC.
Chapter 13 deals specifically with designing/architecting applications for performance. It discusses how performance should be addressed in each phase of the development cycle (analysis, design, development, deployment), and offers tips a checklist for your performance initiatives. The puzzling thing about this chapter is why it is presented at the end of the book instead of towards the front, with all of the other process-related material. It makes much more sense to put this material together up front.
Chapter 14 covers various hardware and network aspects that can impact application performance including: network topology, DNS lookups, and machine specs (CPU speed, RAM, disk).
PART 4 : J2EE Performance
Chapters 15-18 deal with performance specifically with the J2EE APIs: EJBs, JDBC, Servlets and JSPs. These chapters are essentially tips or suggested patterns (use coarse-grained EJBs, apply the Value Object pattern, etc) instead of very low-level performance tips and metrics provided in earlier chapters. You could say that the author is getting lazy, but the truth is that due to huge number of combinations of appserver/database vendor combinations, it would be very difficult to establish a meaningful performance baseline without a large testbed.
Chapter 15 is a reiteration of Chapter 1, Tuning Strategy, re-tooled with a J2EE focus. The author reiterates that a good testing strategy determines what to measure, how to measure it, and what the expectations are. From here, the author presents possible solutions including load balancing. This chapter also contains about 1.5 pages about tuning JMS, which seems to have been added to be J2EE 1.3 acronym compliant.
Chapter 16 provides excellent information about JDBC performance strategies. The author presents a proxy implementation to capture accurate profiling data and minimize changes to your code once the profiling effort is over. The author also covers data caching, batch processing and how the different transaction levels can affect JDBC performance.
Chapter 17 covers JSPs and servlets, with very little earth shattering information. The author presents tips such as consider GZipping the content before returning it to the client, and minimize custom tags. This chapter is easily the weakest section of the book: Admittedly, it's difficult to optimize JSPs since much of the actual running code is produced by the interpreter/compiler, but this chapter either needs to be beefed up or dropped from future editions.
Finally, chapter 18 provides a design/architecture-time approach towards EJB performance. The author presents standard EJB patterns that lend themselves towards squeezing greater performance out of the often maligned EJB. The patterns include: data access object, page iterator, service locator, message facade, and others. Again, there's nothing earth shattering in this chapter. Chapter 19 is list of resources with links to articles, books and profiling/optimizing projects and products.
What's Bad?
Since the book has been published, the 1.4.1 VM has been released with the much anticipated concurrent garbage collector. The author mentions that he received an early version of 1.4.1 from Sun to test with. However, the text doesn't state that he used the concurrent garbage collector, so the performance of this new feature isn't indicated by this text.
The J2EE performance chapters aren't as strong as the J2SE chapters. After seeing the statistics and extensive code samples of the J2SE sections, I expected a similar treatment for J2EE. Many of the J2SE performance practices still apply for J2EE (serialization most notably, since that his how EJB, JMS, and RMI ship method parameters/results across the wire), but it would be useful to fortify these chapters with actual performance metrics.
So What's In It For Me?
This book is indispensable for the architect drafting the performance requirements/testing process, and contains sage advice for the programmer as well. It's the most up to date publication dealing specifically with performance of Java applications, and is a one-of-a-kind resource.
You can purchase Java Performance Tuning, 2nd Edition from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
If all these performance hacks are documented, why doesn't the compiler implement them?
I've often found that will bytecode languages (Java, C#...) the bytecode instructions are made for the language so that the compiler can just throw them out easy peasy, but they seem to overlook the sort of optimizations that C compilers, for example, work hard to implement.
I have drastically cut back on my tech book purchases in recent times but this book will definitely be on my shopping list. The First edition offered many insights into not only getting the best performance from Java but also solid guidelines for when and where to apply optimisations.
As a side note I would disagree about performance being an albatross for Java. Well written Java code can be very high performant just as poorly written code in ANY language can perform slowly. Many of the performance issues associated with Java are inexperienced developers using inappropriate methods and objects.
Do not try to read the dupe, thats impossible. Instead, only try to realize the truth
What truth?
There is no dupe
Java Performance Tuning: A course in C programing
--
http://www.dennistighe.com
there is a difference, you know.
The bn.com link is broken for me, here's the correct ISBN:
0596003773
I don't know which is more depressing, that 2/3 didn't care enough to vote, or that 1/2 of those that did are crazy.
Each String is around 64 bytes of memory minimum. What a stupid decision to make such a fundamental data type so heavy weight.
I have noticed my JAVA programs run considerably faster under the Sun Forte/One IDE. Once the JAVA app is on its own (especially through a browser), it slows considerably. Does anyone else have experience with this phenomenon?
stuff |
The book starts off with three chapters of sage advice about the tools and process of profiling/tuning. Before you spend any time profiling, you have to have a process and a goal. Without setting goals, the tuning process will never end and it will likely never be successful.
No, you have to profile first. Profiling will tell you whether there is even any point in tuning, and, if so, what goals are reasonable.
Java has performance troubles? I thought we were all supposed to deny that. Did I miss a memo or something?
Remember there is a distinction between client- and server-side Java. Java on the server makes me very happy.
We ported some of our internal Java business applications to C# for use with Mono, and emperical results already suggest the solution is several times faster than the Java code. The port was very easy, with each line of Java code mapping onto one line of C# or less. Porting the UI to Gtk# was more difficult, but we find the Gtk# code more maintainable and the UI, along with the Gtk+ WIMP plugin integrates much more nicely with Windows than SWING. We'll be investigating a switch to Linux over the next few months for some of our Point-of-Sales terminals as a result, and it should be easy thanks to the portability of Mono and Gtk#.
We also ported some of our backend tools for use with Mono. In use with the newly released Mono JIT runtime, Mini, we've achieved some truly stunning results. It turns out that some of the optimisations in the new JIT are better than those used by GCC, so once the code is loaded in memory, it performs better than raw C code. Although I don't yet have hard numbers to back up these result (the transition is still in progress), it has to be said that Mono is the real answer to Java performance. Being Open Source, we can also contribute back to the runtime to make it better suit our needs. It also plays nicely with RedHat 9's NPTL threading implementation, which is more than I can say for the current crop of Java JREs.
Why would the users care whether you use a J2EE or PHP4 backend? You must be thinking of Java applets which very few few people actually use for any "web page development". And the chapters 15-18 that talk about J2EE, what's wrong with using J2EE for the generation of webpages and content?
That said for most network centric applications java is plenty fast. Now if we only stopped short of introducing the unbelievable overhead of XML's excessive verbosity...
Your pizza just the way you ought to have it.
Why does programming languages have to be an either or situation? Everyone here assumes that anyone who programs in JAva does not know C/C++...why is that? Can't someone know multiple prog langs? I know many (too many too really list here) and find it asinine that people really think that everyone should just program in one lang.
click me
Perhaps it is more efficient. I say, let the compiler do it for me. Code like this:is much more readable/maintainable than
It does under the hood whenever you use + for concatenation; this is why using String + String in a loop is ineffective: You create a new StringBuffer object per iteration. The solution in this case is to declare the StringBuffer outside the loop and use append() explicitly within.
For concatenating two strings, the concat() method can be faster than using StringBuffer, since it only needs to create a new char[] and do a (fast) arraycopy from the two internal arrays.
Also, everyone should be aware of the 1.4.1 memory leak associated with using StringBuffer's toString() and setLength() methods.
Okay,
flippant comment but let's think about this for a second: The majority of the time the alleged efficiency advantage is small or, as is generally the case, a pointless optimisation. Java coders seem to have the major efficiency/speed hangup - they use it to lord it over scripting programmers but they want/lack/desire the swiftness of C. (And yes, I do program in Java.)
To my mind, this is approching the problem from entirely the wrong direction: CPU time and CPU power are far cheaper than developer time and designer time. Therefore, rather than use some cobbled-together hack, use the standard implementations and take the performance hit.
This will be cheaper, probably 95% as efficient and, most importantly, be 195% easier to maintain or change at a later date. Consider the big picture rather than a single aspect.
NB - YMMV, for certain apps, it really does make sense to break all of the above ideas and principles, but if you REALLY need it to run that fast, you should be using C anyway.
Elgon
Amazingly, Java actually performs very well once the JVM loads. Sure, it can't match uber-efficient c code, but, let's be honest here, how much c code really is efficient? I'm sure it's less than c programmers like to believe. ;)
That said, "slow" performing Java GUI aps are not so much the fault of the platform itself as they are the fault of the Java programmer's inability to deal efficiently with threads.
"Times have not become more violent. They have just become more televised."
-Marilyn Manson
Ick.
The albatross doesn't need killing -- it's already dead. The albatross was hanging from the mariners neck because he had killed it, and by doing so had brought bad luck upon his ship.
Quoting from memory here, because I can't be bothered to go find my copy of the poem:
As I said, that's from memory, so there are probably plenty of mistakes in there, but I'm sure a little googling will turn up a proper copy of the poem.
Don't be an idiot. The size of the standard api does not relate to any inefficiency java has. How can the number of standard classes translate to inefficiency What is the magic number of standard classes to be "just right"?
The best thing about java is the richness of the api. And the size of the documentation. C++/C should take a page from java's book in this department.
You don't have to use the standard classes, go ahead and write the classes you need.
Jonathan
I read the first edition of this book completely. There are some good tips for extracting a few percentage points of improved performance. However, nothing has as profound an impact as simply using a better VM ... for example, many of my applications saw 25%+ speed increases simply by switching from the 1.2.x series VM to the 1.3.x series VM.
Java does a pretty could job as a language of encouraging best practices, i.e. the inclusion of a standard StringBuffer. Extreme optimization at the code level will always be limited given the high abstraction of the language. However, extreme optimization at the VM level is a very real thing, and it doesn't take a whole lot of effort for the Java programmer.
(Score:-1, Wrong)
Java isn't just about applets. In fact, applets are the least used feature of Java -- they're a neat little toy useage. Java is used primarily for back-end code now. Servlets talking to databases, for instance, are where Java is most often found.
Join Tor today!
Previously, the startup slowdown was due to the system having to load, verify, and link the twenty or so classes a simple program depends upon. Pjava and J2ME-CDC solved that by storing an image of the heap with the system classes already loaded, verified, and linked (and quickened) so the system was run-ready almost immediately. I wonder if the J2SE folks picked up on that? Alternatively, they could just be skipping the verify for those classes in the signed rt.jar, and offline preverify them prior to signature - the verifier always was the slow part of the process.
Your point about threads is well taken, and applies more generally to much of java programming. Java's language and libraries make it all to easy to write architecturally-slow programs - you really still have to fully understand what you're doing in order to write a decent program, regardless of the language.
## W.Finlay McWalter ## http://www.mcwalter.org ##
I challenge you to make a C++/C# application that is thread-safe and can scale to millions of pageviews per day without writing a ton of supporting code. With a good J2EE app server, a java coder essentially just has to wrap his thread-unsafe code in a syncronized() statement, and he's done-- his app is now thread-safe.
Additionally, the "cross-platform doesn't matter for sysadmins" is a false statement; our CIO asked our net ops group "what would be the impact of us moving to an Intel platform?" and our sysadmins (after consulting with the coders) replied "absolutely no impact". That made our CIO very, very happy. Again, I challenge you to move your C++ apps from Solaris to Linux, or even to Windows, without any hiccup.
All of these other arguments are very specious: "I don't have enough RAM" will get you a reply of "go down to Fry's and spend $125 on another GB" every time. Processor speeds, even on Sun boxes, is getting to the point where the processor will never be a bottleneck for anything. Sure, java won't run as fast as a natively-compiled app. Neither will perl, php, tcl, or what have you. Raw processor speed is not as important when you have a couple of GHz to play with.
Java would've been far better if they'd stuck to a few basic classes, and let people develop the classes they need as they go.
Well, gosh, you go right ahead and write your own replacement classes for everything that Sun has done already. What's stopping you?
That's exactly why I like Java. They have a lot of good built-in libraries that cover a wide-range of applications. I don't have to reinvent the freaking wheel every time I write an app.
Your hybrid is not saving the environment. Its purpose is to make you feel good about buying something.
The bottleneck in our applications is not how fast whatever server-side language we use, and I imagine this is similar is most IT shops.
Our bottleneck is how fast we can execute lots and lots of stored procedures in our SQL and Oracle databases.
It really hasn't mattered if one of our coders has been terminating loops via try{}catch{}, or ending on a condition.
The most important thing has been, "Does each line, each method, each class do what it's actually supposed to do?"
Our bottlenecks have always been flow back and forth between different systems, including Lotus Domino, Oracle, MS SQL Server, Websphere, etc. etc.
Java is a small player in all this... C++, C#, Fortran, Lisp would not speed this up for us.
That article is the most absurd joke I have ever read. He spends half the article complaining about Java's startup time (which (A) does not apply in any server situation, and (B) is unfair, because you don't count the machine's bootup time when talking about the performance of C programs, do you?).
Then he invents other ways to talk about the startup time without seeming to talk about the startup time (for instance, trussing Hello World results in a ton of output, but naturally that's Java starting up and loading its classes. Again, do you consider what the machine has to do to boot itself up when you're talking about C programs?). I will point out again that Java's startup time is almost irrelevant, especially in a server environment (which is what he's talking about).
The rest of the article is picking on the "jar" tool. jar is a program written in Java. Criticisms against the jar tool no more reflect on Java than criticisms against gzip reflect on C. The fact that jar doesn't do a good job of reporting errors is (A) irrelevant, because it's a developer tool and we know how to read exceptions, and (B) still more irrelevant, because how well it reports errors has nothing to do with what language it was written in. Tons of C programs have lousy error reporting as well, such as a number of Unix utilities I might name.
Further, this article is obviously very old. He's talking about Java 1.1.8, which is what, five years old now? Might as well criticize Linux by talking about obscure video driver bugs that were fixed five years ago. Obviously, that's not the article's fault for having been written so long ago, but it is the parent poster's fault for bringing it up as if it is somehow still relevant.
ZFS: because love is never having to say fsck
The FFT benchmark is a very specific case. Once the JIT kicks in, it's not Java vs C++ anymore, it's the JVM optimizer vs the GCC one. Contrary to popular belief, the GCC optimizer is very good (check out benchmarks vs ICC at coytegulch.com). However, the FFT benchmark is a case where the additional information available to the JIT optimizer allows it to outperform native code. The whole benchmark is so small, it probably even fits in cache, and doesn't really stress any of the performance pitfalls of the language itself. Now, if you have a larger application, that doesn't consist of a single inner-loop, and meanders through a lot of varied code (ie. most real applications) then the performance story will be very different. At that point, Java's performance faults (excessive bookkeeping overhead, object allocation/deallocation, overhead from the JVM, etc) come much more into play.
A deep unwavering belief is a sure sign you're missing something...
I disagree.
You should always try to find the best, most efficient, most cost-effective approach/solution to your problem.
If your internal time is billed out at $50 per hour, and you want to save your company money, you aren't going to spend 4 hours to create a custom garbage collector just to save another 5k of RAM-- you're going to go out and buy another stick of memory.
I agree wrt bad coding habits and the like, but everything has its price. If someone can push an application out the door rapidly that can still be easily maintained and only requires a bit more memory or a bit faster processor, I'm more than willing to expense the money for that new hardware.
Well, there are two ways you can prove it -- write a test... do a million iterations of one, versus a million of the other and watch your RAM usage and time it takes. Alternately, compile it and then use a java disassembler, and look at the resulting code. The string concatination is very heavily optimized, and structures like that where you are concatinating hardcoded strings basically does the equivalent of interning them (there aren't real string objects for those). Compilers are smart. If you concatinate to produce the string, it knows what you are trying to do and can optimize. If you self-optimize and get it wrong (which is what happens when you use a StringBuffer), it doesn't know what you are doing and can't optimize it. Two seconds of google searching turned up this, if you don't want to test it yourself: http://www.precisejava.com/javaperf/j2se/StringAnd StringBuffer.htm
Since other posters have already indicated that gcj /does/ lead to better performance, I think I have a cause for your performance increase beyond "Java sux":
Re-implementation removed the bottleneck.
What kind of profiling did you do against your original Java application? Where was the time being spent? I've worked on some pretty high-performance java applications, and have found them to be quite scalable.
If you're talking about GUI responsiveness (not client/server or high processing interactions), then you may have a point. All the nefarious interactions between the platform-specific GUI toolkits and their OS of choice (this applies both to Windows and Linux) do a lot of very specific optimizations that just can't be done as well cross platform.
Interestingly, the original AWT used components based on native ones for just this reason, but that turned out to be problematic.
Anyway, if you have the intention of supporting your claim that your application had performance problems due to Java itself, I'd be interested in hearing about your profiling process.
-Zipwow
I don't know which is more depressing, that 2/3 didn't care enough to vote, or that 1/2 of those that did are crazy.
Java exception verbosity is a serious problem. Many times I've heard of "java.lang" errors. The correct solution to this problem is to use C-style exception handling:
try {
// code
}
catch (Throwable t) {
System.err.println("segfault");
}
As you can see, Java is every bit as good as C.
The FFT benchmark is a very specific case.
Why? It's smaller than most code, but why does that inherantly benefit Java?
Once the JIT kicks in, it's not Java vs C++ anymore, it's the JVM optimizer vs the GCC one.
That's the whole point. Unless you only care about programs where the entire execution time is a few seconds, the JVM optimisation time isn't going to be much of an issue.
However, the FFT benchmark is a case where the additional information available to the JIT optimizer allows it to outperform native code.
I compiled specifically for the machine I was running on. I tried everything I could to make it faster than Java. For Java VMs, being able to get "additional information" is what always happens. It's not specific to the benchmark.
The whole benchmark is so small, it probably even fits in cache, and doesn't really stress any of the performance pitfalls of the language itself.
The code is 10KB file with a number of critical functions. A good optimiser would have to do inlinging, loop unrolling as well as a lot of data-flow optimisation. I ran it across a range of data sizes, and Java did better at bigger array sizes (until memory bandwidth was the limiting factor). You have it the wrong way around - the smaller the code/data, the more language specific issues show up.
Now, if you have a larger application, that doesn't consist of a single inner-loop, and meanders through a lot of varied code (ie. most real applications) then the performance story will be very different.
Unless your app's performance is dependant on I/O, OS calls or strings, making the application bigger is not going to make things very different. Actually, it can give JVMs a number of extra advantages due to the super-inlining capabilities available to run-time generated code.
At that point, Java's performance faults (excessive bookkeeping overhead, object allocation/deallocation, overhead from the JVM, etc) come much more into play.
I don't know what you mean by "bookkeeping overhead" but C code has to allocate/deallocate memory too, and has problems like memory fragmentation. How things compare with a garbage collector depends on the code, system, JVM etc, but modern JVMs can handle 10s of gigabytes of data in the heap. Simply to say that GC is slow is simplistic. Unless you have code that only runs for a few seconds, "overhead from the JVM" (if by that you mean the optimiser) isn't going to be a problem.
I'm not saying there's not areas where Java is at a disadvantage (I've listed some in this post). In some areas, it's going to remain inherant, but in others, JVMs are becoming advanced enough that issues like run-time optimisation can be a distinct advantage. Anyway, as far as I'm concerned, I have no problems with Java performance for anything I've done, including GUI code.
These days when writing highly optimised web-server code in Java, I have to get a super-accurate timer since Java's standard timer is only accurate to one millisecond, and that's too coarse grained to tell how much different various optimised I add make. This is where all the HTML is dynamically generated for each request btw.
If your internal time is billed out at $50 per hour, and you want to save your company money, you aren't going to spend 4 hours to create a custom garbage collector just to save another 5k of RAM-- you're going to go out and buy another stick of memory.
This reminds me how broken many (most?) corporate accounting systems are. Where I work, for a stick of RAM (or software, or whatever), it would take at least four hours spread over a couple weeks just to figure out who to submit the request to, wait for our "purchasing agent" to get a couple signatures from bureaucrats, wait for the purchase order to work its way to the top of a pile, and finally get the RAM only to discover they ordered the wrong type. All the while, they'll happily pay for labor hours wasted on slow computers with inadequate RAM (for example).
Why there is such a fundamental disconnection between spending money on labor versus spending it on time-saving equipment and software leaves me questioning reality.
Healthcare article at Kuro5hin
How much does that extra development time cost?
Writing ones' own java.lang.String takes time. Writing routines to convert com.donkeybollocks.String to java.lang.String and back again takes time. Supporting it takes time. And time is money. Me, I'd rather spend an extra £100 on a faster processor, or a Gb of RAM, and take a 25% performance improvement.
Come on guys, one of the major wins of the OO methodology is code reuse. Time was when programmers would always have to write their own I/O routines - I thought those days were long-gone. Rewriting fundamental parts of the Java API is just plain silly, unless it has a bug or a serious limitation (eg, it's non-threadsafe).
The more advanced the technology, the more open it is to primitive attack
I don't know what pletorah of things they taught you in CS school, but much of the wisdom they taught some of us can be summarized:
- Big O matters. Optimization of constants is an expensive luxury.
- Reimplementing the wheel for the sake of marginal efficiency is a sure way to get a square and inefficient wheel.
Most algorithms of any common use are provided in the standard libraries of each language. If not there, any algorithm can be implemented in any language by virtue of its Turing-completeness. This guarantees you bigO efficiency, which is what matters in the long run.
The article complains about Java being slow for the sake of its pcode nature. That's a constant factor, not bigO. It's automatically defeated by "CPU is cheap, RAM is cheap", i.e.: constant factor acceleration is cheap.
You better have a good reason to worry about constant factors: if your program demands so much from the machine that the constants make the difference on whether it's practical or not, you better be experimenting with the 'bleeding edge' or there's something really wrong with your program.
Efficient algorithms are used on every language by any programmer worth 2 bucks. Java has the advantage of implementing a bunch of them on standard libraries that work quite well, thank you. Someone who uses bubblesort in Java outside of a classroom is not lazy, he's an idiot. Implementing bubblesort is more complex and expensive than calling Arrays.sort().The same thing actually applies to any programming language.
If your concerns about speed as a typical sysadmin (servers and workstations) or even worse, as a developer, are dominated by constant factors, it's time to go back to take data structures and algorithm analysis at CS school.
Freedom is the freedom to say 2+2=4, everything else follows...
When I write a Java program... if it's too slow today, then, in time, the problem will go away without any more effort on the part of the programmer. In a year from now, we'll certainly have faster computers, which will make up for any speed problems.
On the other hand...
A year from now, we will almost certainly not have CPUs that are suddenly immune from dangling pointers and memory leaks.
In other words, there are not plausible, near-future-forseeable advancements in computing hardware that could fix the worst problems of C/C++. Meanwhile, the near-future advancements in hardware are almost guranteed to fix Java's worst problem.
The same holds true for doing your computing today... regardless of what hardware is available a year from now. Personally, I'd rather have a slow program that could keep running than one that was really fast, but crashed before I could save my work.
Why? It's smaller than most code, but why does that inherantly benefit Java?
>>>>>>
The reason it inheretly benefit Java is because of the characteristics of the Java language. First of all, it's a JIT language. Thus, if you have a tight inner loop, the JIT optimizer can optimize the hell out of it (even more so because it has access to runtime information that the static C++ optimizer does not) and just hand it over to the processor for execution. The JVM isn't even executed again until the loop is over. This situation doesn't invoke any of the language overhead that makes Java slow. This overhead takes many forms. The JVM has a large instruction cache footprint. Java objects all have an extra header containing type information that causes a data cache footprint and impacts memory bandwidth. The garbage collector can be a big problem. As Tannenbaum said, avoiding disaster is more important that optimal performance. The average case allocation/deallocation might be quite fast for a garbage collector, but when an actual collection occurs, you get that "disaster" that you're trying to avoid. The collection process thrashes the cache and occupies the application for a (comparatively) long time. When a function is invoked, the JVM has to check to see if the JIT has the code already cached. This takes time. Move beyond that to the Java APIs themselves. The Java APIs are designed for purity and ease of use. APIs like the C++ STL are designed for pure performance. For example, a dynamic cast is inherently slow, by the nature of the operation. Yet, the Java Collection APIs require them for every access. All Java class methods are by default indirect. Last time I measured (on a PII 300) indirect calls are about 10 times slower than direct calls. A small numeric benchmark doesn't hit any of these performance issues, but real application code hits them, hard.
A deep unwavering belief is a sure sign you're missing something...
You only need 4 bytes to make reflection work. Each object has a pointer to what class it is. The class information has everything else, the vtable so to speak, what interfaces are implemented, etc. All String objects have one single pointer to a common String class object the defines what a String is, what its members are, what its methods are, etc. everything needed for reflection. Think of the vtable as being more than just an array of method pointers, but meta information (the class object) about the object. More than just a vtable. Therefore, reflection requires no overhead really, since an OO language needs a vtable pointer.
The price of freedom is eternal litigation.
There's an additional 16 bytes involved in the object class descriptor pointer and the reference to the object's monitor (*2 - one for the String and one for the char[], which is a fully fledged object in its own right), plus probably a couple of bytes overhead for the memory allocator. About 32 bytes seems reasonable. I think the point to make is, though, there is no _sensible_ way of making the string any smaller without sacrificing performance. Plus the objects have the ability to share the array between two strings that have similar data (say one is a substring of another) and that _substantially_ reduces memory requirements. I'd say the Java string implementation is about as good as it gets.
20% sounds like an inflated number. The typical app spends most of its time waiting for I/O or doing silly stuff for user interaction. A 20% overall difference would imply what, 50%, 100% slower when it's actually working?
There's some overhead, but it's never that bad. Sure, the overhead matters, which is why there's an investment on improving VM technology, providing access to native operations, etc.
But also the worst overhead offenders are not VM issues, but application design issues: blocking I/O, threading bugs, NOT using multithreading when you should, etc. Also, using Swing/AWT in a non-trivial GUI. I'm beginning to consider Swing/AWT just a giant bug.
However, let's assume the 20% speed difference in an application...
It's not that constant factors don't matter at all, it's that they matter the least. And when you have so many more important problems to fix, they take the last place in the priority list.
By definition, choosing your implementation language is an early decision that takes place long before that list is filled up. Although speed is always a concern, algorithmic speed is more important than PL speed, and independent of it. So PL speed shouldn't have that much to do with the decision.
Saving 20% in hardware is great, and the efficiency marketing advantage is important too. But those advantages are worth nothing if your application is buggier, less extendable, less flexible than your competitors, and specially if it gets to the market AFTER your competitors.
Developing applications in C is more expensive and complicated than developing them in Java, and the difference is typically more than the difference in speed. (I'm not saying that C applications are inherently worse than Java apps, just that to develop the same application with the same extensibility, features and stability takes more time, and a bunch of non-standard libraries).
Development costs add much more quickly than hardware costs, and unlike hardware costs, development costs are not guaranteed a return in performance. These are not dollars and cents, but hundreds and tens of dollars: development is more expensive than hardware.
Then you go to the client 6 months after your competitors and try to sell them the application. If they haven't already bought from the competition, you'll try to convince them that although your application is more expensive, and altough it hasn't been tested in the market for as long as the other ones, and although they'll need a C programmer versed in your favorite non-standard libraries to maintain it (you do give them API documentation and the tools to maintain it, right?), your application will save them a few bucks in hardware.
Unless the difference in hardware costs has more than 4 digits, I think your customer will advice you to take an accounting class.
If the difference is more than 4 digits, you are pushing the technology and you need to care about constant factors.
Either that or you're not dealing with a typical application. For example, a scientific analysis program that spends most of its time in pure computation needs all the juice it can get. Although I understand Java works fine for pure computational tasks.
Now, if you can make your applications in C as cheap, fast, and safely as with Java, then you have great C developers so you should just keep doing that. Most people can't.
Freedom is the freedom to say 2+2=4, everything else follows...