Java 6 introduced a mechanism to store ASCII characters inside byte instead of a char. This feature was removed again in Java 7. However, it is coming back in Java 9, except this time round, compaction is enabled by default and byte is always used.
||Computational Complexity of BigInteger.multiply() in Java 8
BigInteger has new algorithms for multiplying and dividing large numbers that have a better computational complexity than previous versions of Java. A further improvement would be to parallelize multiply() with Fork/Join.
||Checking HashMaps with MapClashInspector
Java 8 HashMap has been optimized to avoid denial of service attacks with many distinct keys containing identical hash codes. Unfortunately performance might degrade if you use your own keys. In this newsletter we show a tool that you can use to inspect your HashMap and view the key distribution within the buckets.
||Intersection Types to give Lambdas Multiple Personalities
Lambdas are often described as anonymous inner classes without the boilerplate code. However, lambdas are more powerful. Firstly, a lambda does not always result in a new object. Secondly, "this" refers to the outer object. Thirdly, a lambda object can implement multiple interfaces. In this newsletter we will look at this third feature, where cast expressions use intersection types to produce lambdas with several interfaces.
||ByteWatcher from JCrete
Even though standard Java is not real-time, we often use it in time-sensitive applications. Since GC events are often the reason for latency outliers, such code seeks to avoid allocation. In this newsletter we look at some tools to add to your unit tests to check your allocation limits.
||Parallel Parking (Follow-up)
Heavily contended concurrent constructs may benefit from a small pause after a CAS failure, but this may lead to worse performance if we do more work in between each update attempt. In this follow-up newsletter, we show how adding CPU consumption can change our performance characteristics.
What is faster? Synchronized or Atomic compare-and-set? In this newsletter we look at some surprising results when we run Java on the new i7 chip.
||Performance Puzzler With a Stack Trace
In this newsletter, we present a little performance puzzler, written by Kirk Pepperdine. What is happening with this system? There is only one explanation and it can be discovered by just looking at the stack trace.
||Memory Usage of Maps
In this newsletter we measure the memory requirements of various types of hash maps available in Java. Maps usually need to be threadsafe, but non-blocking is not always the most important requirement.
||Delaying Garbage Collection Costs
The garbage collector can cause our program to slow down at inappropriate times. In this newsletter we look at how we can delay the GC to never run and thus produce reliable results. Then, instead of actually collecting the dead objects, we simply shut down and start again.
||Cost of Causing Exceptions
Many years ago, when hordes of C++ programmers ventured to the greener pastures of Java, some strange myths were introduced into the language. It was said that a "try" was cheaper than an "if" - when nothing went wrong.
||Serialization Size of Lists
What has a larger serializable size, ArrayList or LinkedList? In this newsletter we examine what the difference is and also why Vector is a poor candidate for a list in a serializable class.
||Generating Static Proxy Classes - 2/2
In this newsletter, we show how the Generator described in our previous issue can be used to create virtual proxy classes statically, that is, by generating code instead of using dynamic proxies.
||Generating Static Proxy Classes - 1/2
In this newsletter, we have a look at how we can create new classes in memory and then inject them into any class loader. This will form the basis of a system to generate virtual proxies statically.
Escape analysis can make your code run 110 times faster - if you are a really really bad programmer to begin with :-) In this newsletter we look at some of the places where escape analysis can potentially help us.
||Java Memory Puzzle Explained
In this newsletter, we reveal the answer to the puzzle from last month and explain the reasons why the first class sometimes fails and why the second always succeeds. Remember this for your next job interview ...
||Java Memory Puzzle
In this newsletter we show you a puzzle, where a simple request causes memory to be released, that otherwise could not. Solution will be shown in the next newsletter.
||Discovering Objects with Non-trivial Finalizers
It is well known that implementing a non-trivial finalize() method can cause GC and performance issues, plus some subtle concurrency bugs. In this newsletter, we show how we can find all objects with a non-trivial finalize() method, even if they are not currently eligible for finalization.
In this newsletter, we show two approaches for listening to bytes on sockets. The first uses the Delegator from our previous newsletter, whereas the second uses AspectJ to intercept the call to Socket.getInput/OutputStream. We also write an MBean to publish this information in JConsole.
||Starvation with ReadWriteLocks
In this newsletter we examine what happens when a ReadWriteLock is swamped with too many reader or writer threads. If we are not careful, we can cause starvation of the minority in some versions of Java.
Prior to Java 1.4, ThreadLocals caused thread contention, rendering them useless for performant code. In the new design, each thread contains its own ThreadLocalMap, thus improving throughput. However, we still face the possibility of memory leaks due to values not being cleared out of the ThreadLocalMap with long running threads.
||Polymorphism Performance Mysteries Explained
In this newsletter, we reveal some of the polymorphism mysteries in the JDK. The HotSpot Server Compiler can distinguish between mono-morphism, bi-morphism and poly-morphism. The bi-morphism is a special case which executes faster than poly-morphism. Mono-morphism can be inlined by the compiler in certain circumstances, thus not costing anything at all.
||Polymorphism Performance Mysteries
Late binding is supposed to be a bottleneck in applications - this was one of the criticisms of early Java. The HotSpot Compiler is however rather good at inlining methods that are being called through polymorphism, provided that we do not have very many implementation subclasses.
||Instrumentation Memory Counter
Memory usage of Java objects has been a mystery for many years. In this newsletter, we use the new instrumentation API to predict more accurately how much memory an object uses. Based on earlier newsletters, but revised for Java 5 and 6.
||Are you really Multi-Core?
With Java 5, we can measure CPU cycles per thread. Here is a small program that runs several CPU intensive tasks in separate threads and then compares the elapsed time to the total CPU time of the threads. The factor should give you some indication of the CPU based acceleration that the multi cores are giving you.
As developers we often hear that performance often comes at the price of good design. However when we have our performance tuning hats on, we often find that good design is essential to help achieve good performance. In this article we will explore one example of where a good design choice has been essential in an effort to improve performance.
||Safely and Quickly Converting EJB3 Collections
When we query the database using EJB3, the Query object returns an untyped collection. In this newsletter we look at several approaches for safely converting this to a typed collection.
||Deadlock Detection with new Locks
Java level monitor deadlocks used to be hard to find. Then along came JDK 1.4 and showed them in CTRL+Break. In JDK 1.5, we saw the addition of the ThreadMXBean, which made it possible to continually monitor an application for deadlocks. However, the limitation was that the ThreadMXBean only worked for synchronized blocks, and not the new java.util.concurrent mechanisms. In this newsletter, we take a fresh look at the deadlock detector and show what needs to change to make it work under JDK 1.6. Also, we have a look at what asynchronous exceptions are, and how you can post them to another thread.
||Copying Arrays Fast
In this newsletter we look at the difference in performance between cloning and copying an array of bytes. Beware of the Microbenchmark! We also show how misleading such a test can be, but explain why the cloning is so much slower for small arrays.
||Young vs. Old Generation GC
A few weeks ago, I tried to demonstrate the effects of old vs. new
generation GC. The results surprised me and reemphasized how important GC
is to your overall program performance.
||What is faster - LinkedList of ArrayList?
||Performance Surprises in Tiger
||OutOfMemoryError Warning System
||Autoboxing Yourself in JDK 1.5
||MemoryCounter for Java 1.4
||Multi-Dimensional Arrays - Creation Performance
||Too many dimensions are bad for you
||Results of last survey
||Treating Types Equally - or - Life's Not Fair!
||Disassembling Java Classes
||Nulling variables and garbage collection
||Follow-up to Loooong Strings
||When arguments get out of hand...
||Counting bytes on Sockets
||Follow-up to JDK 1.4 HashMap hashCode() mystery
||HashMap requires a better hashCode() - JDK 1.4 Part II
||Charting unknown waters in JDK 1.4 Part I
||Speed-kings of inverting booleans
||Counting Objects Clandestinely
||Counting Objects Clandestinely - Follow-up
||Determining Memory Usage in Java
||Circular Array List
||Self-tuning FIFO Queues
||Socket Wheel to handle many clients
||Implementing a SoftReference based HashMap
Java deadlocks can be tricky to discover. In this very first Java Specialists' Newsletter, we look at how to diagnose such an error and some techniques for solving it.