Hidden evils of Java's boolean array (boolean[])
Consider this piece of code which allocates a boolean array of 100,00:
boolean[] array = new boolean[100000];
What should the size of this array be?
Considering that a boolean can just be either true or false, every element in the array only needs a single bit of space each. Thus, the size of our boolean array in bytes should be:
100,000/8 + (overhead of array object) = 12,500 bytes + (overhead of array object)
But there lies the hidden evil....
The Evil Inside
As it turns out, when you allocate a boolean array, Java uses an entire byte for each element in the boolean array!
Thus the size of the boolean array is in fact:
100,000 bytes + (overhead of array object)
Remedy
So is there any way not to use the 7 extra bytes when you only need the 1 bit? Its here that the java.util.BitSet class comes to rescue.
The BitSet class does indeed use a single bit to represent a true/false boolean value. Its implementation uses an array of 'long' values, where each bit of the long value can be individually manipulated to set any position in the entire BitSet to true or false.
The BitSet implementation does add a bit of cpu overhead since it has to shift and or bits together to set the value of the bit in the correct position. Thus you need to weigh the cost of memory savings versus the extra cpu overhead when using this class.
Benchmark
As an example, here is a screenshot from the YourKit profiler, showing the memory used by a boolean array and a bitset object, both 100000 element long:
As can be be seen:
The boolean array takes: 100,000 + 16 (array overhead) = 100,016 bytes
The BitSet object only takes :
100,000 / 64 (size of long) = 1562.5 = 1563 long values after rounding1563*8 + 16 (array overhead) = 12, 520 bytes
A few extra bytes are added for the BitSet object itself and the extra 2 fields that it contains.
To put things in perspective, here is a graph showing the space occupied by both for 100,000 elements:
Conclusion
As can be seen from the graph above, using the BitSet instead of a boolean[] can save you tons of memory at the cost of just a few extra cpu cycles
Hidden evils of Java's String.split() and replace()
If you code in Java, you have inevitably used the String.split() and String.replace() (including replaceFirst() and replaceAll()) functions.
And why wouldn't you? They are much more convenient than using the Java Regular Expressions API where you need to create a 'Pattern' object, and possibly a 'Matcher', and then call methods on those.
However, all convenience comes at a price!
The Evil Inside
In this case, the String.split() and String.replace*() methods (with the sole exception of String.replace(char, char) ) internally use the regular expression apis themselves, which can result in performance issues for your application.
Here is the String.split() method:
Notice that each call to String.split() creates and compiles a new Pattern object. The same is true for the String.replace() methods. This compiling of a pattern each time can cause performance issues in your program if you call the split() or replace() functions in a tight loop.
Benchmark
I tried a very simple test case to see how much the performance is affected.
The first case usedString.split() a million times:
In the second case, I just changed the loop to use a precompiled Pattern object:
Benchmark Results
Here are the average results of 6 test runs:
Time taken with String.split() : 1600ms
Time taken with precompiled Pattern object: 1195 ms
Conclusion
Note that I used an extremely simple regular expression here which consists of just a single 'space' character and it resulted in > 25% decrease in performance.
A longer more complex expression would take longer to compile and thus make the loop containing the split() method even slower compared to its counterpart.
Lesson learned: It is good to know the internals of the APIs you use. Sometimes the convenience comes at the price of a hidden evil which may come to bite you when you are not looking.
Chronon 2.2 released
This is mainly a bugfix release for all components.
Some enhancements to the Debugger UI:
Import/Export available for 'Post Execution Logging' and 'Timeline' views
Servers tab now has 'Record' button in main toolbar
Recording Server
Bugfixes for all 3 components: recordingserver.war, controller and recorder.jar.
Each component in this release can be updated indepently.
Thus for example, if you dont want to update the controller on each box, you can just replace the recorder.jar files with the updated one and leave the rest still running.
If however you are updating from a beta version, you will need to update all 3 components at once.
Grab the latest version from our download page now!
Chronon Step-by-Step Tutorial
Still don't think you are utilizing Chronon to its maximum potential?
We have released a Step-by-Step Chronon Tutorial, where you can download a sample eclipse project and have us walk you through debugging it using Chronon, explaining every single feature.
It takes less than 10 minutes to go through the entire tutorial and by the end you will become a master of Time Travel!
Using Chronon with Intellij IDEA
For all the Intellij IDEA users out there dying to use Chronon, we have now published a detailed guide on Using Chronon alongside Intellij IDEA
GWT support added in Chronon 2.1.2
We have updated the Chronon Eclipse plugin to support the Google GWT plugin. You need GWT plugin version 2.4.2 or higher for the Chronon plugin to be enabled for it.
With the GWT support:
- You can record GWT applications easily in development mode.
- The GWT 'Development mode' view has the Chronon 'blue' stop button that is enabled when you are recording a GWT application. Make sure to use that instead of the 'red' button to stop your GWT applications, otherwise the recording wont be saved properly.
Emergency bugfix update for Chronon Recording Server
We have just updated the Chronon Recording Server to version 2.1.0.296 with an emergency bugfix update.
The update can be downloaded from the download page on our website:
http://chrononsystems.com/download/
Bug Details
The bug occurs when a recording is 'split' at preset time intervals (eg 1 hour), by the Recording Server and results in a corrupt recording.
The bug is inside the Chronon Recorder and during a 'split' can produce an invalid recording, which will throw an exception during the unpack phase. If you try to unpack the recording inside eclipse, the Chronon eclipse plug-in will show an error saying the recording is corrupt. The exception/error will show itself near the end of the unpack phase ( ie, after atleast 90% of the way through).
Fix
To fix the bug, download the latest recording server zip file and just replace the recorder.jar files in your recording server installation with the updated version in the new recording server zip.
The current recorder .jar version with the bugfix is 2.1.0.296. If you are using that version or higher, then you are fine, otherwise you need to update.
ACKNOWLEDGMENT
Our thanks to Steven M, who reported this issue. We fully support your reporting of issues and we appreciate it when people work with us to identify and solve the problem.
Java Bytecode manipulation : Tools of the trade
Since the Chronon recorder uses bytecode instrumentation to record your java applications, I thought I would list some of the tools we use to help us with it:
The de-facto Java framework for bytecode manipulation. The ASM framework is the fastest, most flexible and well known framework around for doing bytecode manipulation. At the time of writing its the only framework that supports the Java 7 class file format. If you are trying to choose a framwork for bytecode manipulation, stop, just learn and use ASM.
This eclipse plugin can automatically show you the bytecode for java file open in your editor. It can also show the corresponding ASM code that would be needed to generate the said bytecode. It will help you understand both bytecodes and the ASM framework better.
This free tool, made by the same guys who make JProfiler, is the most comprehensive way to view your generated .class files. It can show you the bytecodes individually for a method along with things like the local variable table, exceptions table, constant pool, etc. Its a must have, in my opinion, if you are fiddling around with Java byetcodes in any way.
Chronon Time Travelling Debugger
This may sound like self promotion, but I remember the time before Chronon was born and each time we would run into issues with the generated bytecode, (which btw you will at some point too, no matter how hard you try not to), it would take hours trying to use the standard debugger or littering our code with println() statements everywhere before we found the root cause. Now if we find any error in the generated bytecode, we just look at the Chronon recording of the executed code in the Time Travelling Debugger and can find root cause in minutes.
JVM 5 is the new IE 6
Note that I mentioned JVM 5, not Java 5.
Since Chronon requires running on JVM 6, we do get people time to time asking "Does that mean Java 5 is not supported?".
Backward Compatibility
It seems some people still don't understand that you can run Java 5 code on JVM 6. The JVMs are, and have always been, fully backward compatible.
This also means, that you can still write your code as Java 5 and even use JVM 5 to compile and build your application, but during deployment you can choose JVM 6 instead of JVM 5 and gain all the advantages of using a more recent JVM while making sure your code still can, if really needed, run on JVM 5.
Disadvantages of JVM 5
The JVM 5 is over 7 years old. It was even End Of Life'd over 2 years ago. That means it won't be receiving any more updates, so if you run into a jvm bug, tough luck... On Macs, its not even possible to install JVM 5 unless you use some hacks.
Frankly, why anyone would use a a 7 year old technology which won't receive any new updates, when a perfectly good alternative is available, is beyond me!
Advantages of JVM 6
The JVM 6 has been with us for > 5 years now and is still very much under active development. It has had 29 updates so far and is used by millions. It has much better performance than JVM 5 and the vast number of updates have ensured it is pretty damn stable.
Conclusion
At this point it baffles me that enterprises are sticking with a 7 year old, discontinued technology which has a perfectly good replacement which performs better and gets active updates. JVM 5 is the new IE 6 and like IE 6, it would be good for everyone if it was completely eradicated from this world.
Recording Server improvements since beta
Now that the Chronon Recording Server is out of beta, here are some changes we made to it based on a lot of feedback from our customers to improve the experience for everyone:
Installation Experience
The complex installation procedure of the Recording Server was among the biggest complaints during the beta period, so we sought to make it much more simpler.
The complaints centered around an understanding of the various ports used for communication and the high amount of configuration needed. We have cut down on both in this release.
The biggest change we made was with respect to the Recording Server .war file itself. During the beta period, you had to put a special configuration file to tell the Recording Server which port to listen on. This was confusing in many ways:
- The xml file with the context parameter was specific to the container, so you had to figure out how to pass the context parameter for your specific container.
- The mention of port itself was confusing to a lot of people. They couldn't differentiate between the port used for accessing the web ui in the container and the port at which the recording server was listening. We would get frequent complaints like "I configured port 80 for the recording server, but when I type localhost:80/recordingserver nothing happens". And we would have to explain that the web ui was still running at the port of the container it was deployed on, eg localhost:8080/recordingserver. But by this time it was all too confusing for the user.
We have made the experience much simpler now, by removing the need for the xml file entirely. Now you just deploy the .war file normally in your container. When the recording server is first accessed, it will ask the user to specify a port to listen for controllers.
This has multiple benefits:
- No xml file needed to configure the port. Its all done in the UI and can also be changed directly from the UI at any point.
- Since the user accessed the recording server web UI the first time using the port of the container in which it was deployed, eg by using localhost:8080/recordingserver, he no longer has confusions as to differentiating between the port at which to access the UI and the port at which the Recording Server listens.
- Since the UI explicitly states that the port the user is specifying is the one at which the recording server will be listening to controllers, when editing the controller config file, the user knows exactly which port number to use.
Result - Install in < 2 mins
We have even made a video of the recording server installation along with 2 controllers. The video is < 2 mins in length and goes to show how simple it is to install the recording server now.
Running Controller without admin privileges
Another issue during the beta period was some people not having admin access to install the controller and instead of getting admin permission, they wanted to quickly evaluate the product. We have now updated the documentation to show how to use the Controller temporarily without requiring administrator privileges.
Thread Dump
The Recorder Status panel in the Recording Server now has a button to get a Thread Dump of the application being recorded. Can come in handy if your application freezes for some reason or if you just want to know what is going in all those threads.
Recording for long periods of time
We even made a big change with the recorder to allow running it for long periods of time.
Previously we were using a custom thread local mechanism which needed you to specify the total number of threads created in advance. This was set by default to a high number like 5000. However, there are many programs out there that do not use thread pooling and would create and destroy threads, moving the thread id number to cross whatever 'max' value you put.
Thus we decided to use a different algorithm now, which completely removes the need for specifying a max value. You can create and destroy as many new threads as you want now!
This has made the configuration simpler both in the Recording Server UI and the Chronon Eclipse plugin, since there are no longer any fields needed for specifying maximum threads.



