Skip to main content

Posts

Why I don't like System.gc()

I wrote this for internal-to-my-company consumption, but I couldn't find a reasonable place to put it. And then I remembered I had a blog. The question to me was whether is ever made sense to do a System.gc() , and, more specifically, whether it made sense to do System.gc() followed by System.runFinalization() . I can't claim it is always wrong. It suffers from what some people call the Politician's syllogism : Something must be done, this is something, therefore we must do it. There's no control over GC other than a big red button labeled "System.gc()", so this is always the something that must be done. In practice, the biggest problem with System.gc() is that what it does is rather unpredictable. In fact, there's no guarantee that it will do anything. In fact, Hotspot has a -XX:DisableExplicitGC flag to stop it from doing anything. So, it can sometimes solve an immediate problem in a system-dependent way, but you are introducing a signi...

Lightweight Asynchronous Sampling Profiler

I finally got off of my lazy elbows and wrote a proof-of-concept sampling profiler for public consumption based on the Hotspot JVM's AsyncGetCallTrace interface. The benefit of using this interface to write a profiler is that it can gather stack traces asynchronously. This avoids the inaccuracies of only being able to profile code at safe points, and the overhead of having to stop the JVM to gather a stack trace. The result is a more accurate profiler that avoids the 10-20% overhead of something like hprof. For a more thorough explanation as to why this is interesting, see my 2010 writeup on the subject . Another feature of the profiler is that it will tell you what stack traces are being executed, rather than, like many sampling Java profilers, what stack traces could be executed. That is, with traditional profilers, if you stop the VM and ask it for stack traces, it will tell you all of the stack traces from all of the threads that are not currently blocked. This prof...

Transactional Hardware on x86

While I'm posting anyway, I might as well mention the big concurrency news of the day: the new transactional memory specification from Intel. Transactional memory sounds a lot like what it is. Your code begins a transaction and continues to execute it until it ends, performing some memory writes along the way. If there are no conflicting transactions (i.e., transactions that write to the same memory that your code wrote) executing at the same time as yours, your transaction will end normally and commit your memory writes. If there are conflicting transactions, your transaction will abort and roll back your writes. Transactional memory on x86 will come in two flavors: Hardware Lock Elision (HLE), which consists of XACQUIRE and XRELEASE instruction prefixes. These can optimistically turn lock regions into transactions. What's the advantage? Well, transactions can execute concurrently, as long as they aren't writing to the same memory. Locks are serialized: only one ...

Update to the Allocation Instrumenter

A couple of years ago, I open-sourced a tool that lets you instrument all of the allocations in your Java program . Some quick updates today: It now supports JDK7. You can now optionally use it to instrument constructors of a particular type, instead of allocations. So, if you wanted to find out where your Thread s were being instantiated, you could instrument them with a callback that invokes Thread.dumpStack(). I know that most of the readers of this blog are more interested in concurrency, and that it has been a very, very long time since I posted. The spirit is willing, but the flesh is insanely busy... I have it in mind to do a post that discusses a bunch of strategies for doing efficient non-blocking concurrency in C++, because the attempts are very amusing, but I haven't had the chance to sit down and do it.

Scala / Java Shootout

I should probably comment on this paper from my colleague Robert Hundt , where he writes the same benchmark in Java, Scala, Go, Python and C++ ( TL;DR here ). Short version: Initially, C++ was faster than Scala, and Scala was faster than Java. I volunteered to make some improvements, which ended up with the C++ and Java implementations being about the same speed. Some C++ hackers then went and improved the C++ benchmark by another ~6x, and I didn't think I should go down that road. Imagine my surprise when I got this email from a friend of mine this morning: Date: Fri, 3 Jun 2011 03:20:48 -0700 Subject: Java Tunings To: Jeremy "Note that Jeremy deliberately refused to optimize the code further, many of the C++ optimizations would apply to the Java version as well." Slacker. Gee, thanks for making me look good, Robert. (Actually, I had approved that language, but I didn't realize anyone would actually read the paper. :) ) Anyway, I was not just being obdurate here;...

Java Puzzlers@Google I/O

Josh Bloch and I gave one of his Java Puzzlers talk at Google I/O this year. If you hate Java, you can waste a perfectly good hour listening to us make unfunny jokes at its expense.

Cliff Click in "A JVM Does What?"

Cliff Click gave a very good talk at Google last week. For your viewing enjoyment: The slides are available here . (For those who watched it: The inventors of bytecode were in the audience. I think he was just used to making that joke elsewhere.)

JavaOne Talk Cancelled

Because I am a Google employee, my talks are not happening . Apologies to any interested parties. I'm going to try to give the talks in another venue, or at least to use the blog as a venue for some of the topics I wanted to cover.

Why Many Profilers have Serious Problems (More on Profiling with Signals)

This is a followon to a blog post I made in 2007 about using signal handling to profile Java apps . I mentioned in another post why this might be a good idea , but I wanted to expand on the theme. Hiroshi Yamauchi and I are giving a talk at this year's JavaOne . Part of this talk will be about our experiences writing profilers at Google, and in preparing for it, I realized my previous entry on this subject only told half the story. The topic of the original post is that there is an undocumented JVMTI call in OpenJDK that allows you to get a stack trace from a running thread, regardless of the state of that thread. In Unix-like systems, you can use a SIGPROF signal to call this function at (semi-)regular intervals, without having to do anything to your code. The followon post, intended to describe why you would use this, described a couple of things that are true: That it tells you what is actually running on your CPU, not just what might be scheduled, which is what profilers ...

Garbage Collection, [Soft]References, Finalizers and the Memory Model (Part 2)

In which I ramble on at greater length about finalizers and multithreading, as well as applying that discussion to SoftReferences . Read Part 1 first . It explains why finalizers are more multithreaded than you think, and why they, like all multithreaded code, aren't necessarily going to do what you think they should do. I mentioned in the last entry that a co-worker asked me a question about when objects are allowed to be collected. My questioner had been arguing with his colleagues about the following example: Object f() { Object o = new Object(); SoftReference<Object> ref = new SoftReference<Object>(o); return ref.get(); } He wanted to know whether f() was guaranteed to return o , or whether the new Object could be collected before f() returned. The principle he was operating under was that because the object reference was still on the stack, the object would not be collected. Those of you who read the last entry will know better, of course. To put it in...

Garbage Collection, References, Finalizers and the Memory Model (Part 1)

A little while ago, I got asked a question about when an object is allowed to be collected. It turns out that objects can be collected sooner than you think. In this entry, I'll talk a little about that. When we were formulating the memory model, this question came up with finalizers. Finalizers run in separate threads (usually they run in a dedicated finalizer thread). As a result, we had to worry about memory model effects. The basic question we had to answer was, what writes are the finalizers guaranteed to see? (If that doesn't sound like an interesting question, you should either go read my blog entry on volatiles or admit to yourself that this is not a blog in which you have much interest). Let's start with a mini-puzzler. A brief digression: I'm calling it a mini-puzzler because in general, for puzzlers, if you actually run them, you will get weird behavior. In this case, you probably won't see the weird behavior. But the weird behavior is perfectl...

A Note on the Thread (Un)safety of Format Classes

I recently got a note on another blog post asking this question: I have a general question on the thread safety and this is not directly related with your blog. I would appreciate if you could post it on your blog. I have a class that has only one static method that accepts two string parameters and does some operation locally (as shown below). Do I need to synchronize this method? public class A {   public static boolean getDate(String str, String str2){     SimpleDateFormat formatter =       new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");     boolean isBefore = false;     Date date1;     Date date2;     try {       date1 = formatter.parse(str);       date2 = formatter.parse(str);       isBefore = date1.after(date2);     } catch (Exception...

Allocation Instrumenter for Java

In brief: We've open sourced a tool that allows you to provide a callback every time your program performs an allocation. The Java Allocation Instrumenter can be found here. Give it a whirl, if you are interested. One thing that crops up a lot at my employer is the need to take an action on every allocation. This can happen in a lot of different contexts: The programmer has a task, and wants to know how much memory the task allocates, so wants to increment a counter on every allocation. The programmer wants to keep a histogram of most frequently accessed call sites. The programmer wants to prevent a task from allocating too much memory, so it keeps a counter on every allocation and throws an exception when the counter reaches a certain value. Because of the demand for this, a few of us put together a tool that instruments your code and invokes a callback on every allocation. The Allocation Instrumenter is a Java agent written using the java.lang.instrument API and ASM . Each al...

Cliff Click on Java-vs-C Performance

Cliff Click has a terrific post on Java-vs-native-code performance . Recommended. Cliff is the Chief JVM Architect at Azul Systems, was the lead designer behind Hotspot's server JIT compiler, and is an all-around smart guy. His main drawback is that he (apparently) gets dragged into flamewars on YouTube's comment section.

How Hotspot Decides to Clear SoftReferences

I got asked about this twice in one day, and I didn't know the answer, so I sat down and puzzled it out a bit. A SoftReference is a reference that the garbage collector can decide to clear if it is the only reference left to an object, and the GC decides (through some undefined process) that there is enough memory pressure to warrant clearing it. SoftReferences are generally used to implement memory-sensitive caches. A mistake many people make is to confuse it with a WeakReference , which is a reference that, if it is the only reference left to the object, the garbage collector will aggressively clear. I got asked how Hotspot's GC actually decides whether to clear SoftReferences. Twice. On the same day. (Hotspot is the Sun / OpenJDK JVM). The answer was that I had no idea, so I had to go look it up. Here is what I found out; I hope it is a useful reference for someone (pun intended). First, there is a global clock variable that is set with the current time (in millis)...

Volatile Arrays in Java

I get asked a lot about how the volatile keyword interacts with arrays, so it is probably worth a blog post on the subject. Those of you who have read my posts on volatile ( Volatile Fields and Synchronization , Volatile Does Not Mean Atomic and, most importantly, What Volatile Means in Java ) will have a pretty good idea of what volatile means, but it is probably worth it to provide a reminder. Basically, if you write to a volatile field, and then you have a later read that sees that write, then the actions that happened before that write are guaranteed to be ordered before and visible to the actions that happen after the read. In practice, what this means is that the compiler and the processor can't do any sneaky reordering to move actions that come before the write to after it, or actions that come after the write to before it. See my post on What Volatile Means in Java for more detail. With that out of the way, let's go through some examples of what you can do with vol...

Welcome!

Mailinator's Paul Tyma linked to me . If you are following from that link, the relevant blog entry you are looking for is probably this one, specifically, the entry labeled "visibility" .

Faster Logging with Faster Logger Classes

Today, I'll discuss a little tweak I made to java.util.Logging that made my logging throughput double. I want to use it as an illustration that it often isn't very difficult to improve the performance of concurrent code by doing things that are actually pretty easy to do. So, "I" have an application that is running a couple of hundred threads on an 8-core machine, and it wants to log about 2MB a second using java.util.Logger . When I say "I have", I actually mean "someone else has", because if "I" had to log a megabyte a second, there is no way I would use java.util.Logger to do it. Still, we all make our choices. When I came to this code, it was already doing sensible things like buffering its output. It wasn't doing something more complicated, like using a dedicated logging thread. It could log about 1MB a second, and was chewing through CPU pretty rapidly. I just decided to run our profiler on the code and see where the bot...

Small Language Changes for JDK7

For those who haven't been paying attention, there is a new project from Sun to attract proposals for small language changes to JDK7 . Even in the first day of open calls for proposals , the entries have been very interesting: Strings in Switch, a proposal from Joe Darcy to be able to use Strings in switch statements. Automated Resource Blocks, a proposal from Josh Bloch to be able to say things like: try (BufferedReader br = new BufferedReader(new FileReader(path)) { return br.readLine(); } instead of: BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); } based on having BufferedReader implement a Disposable interface. Block expressions, a proposal from Neal Gafter to be allow things like: double pi2 = (double pi = Math.PI ; pi*pi)**; // pi squared* Basically, the principle here is that the (parenthesis-delimited) block would return a value. Exception handling improvements, another proposal from Neal Gaft...

Date-Race-Ful Lazy Initialization for Performance

I was asked a question about benign data races in Java this week, so I thought I would take the opportunity to discuss one of the (only) approved patterns for benign races. So, at the risk of encouraging bad behavior (don't use data races in your code!), I will discuss the canonical example of "benign races for performance improvement". Also, I'll put in another plug for Josh Bloch's new revision of Effective Java (lgt amazon) , which I continue to recommend. As a reminder, basically, a data race is when you have one (or more) writes, and potentially some reads; they are all to the same memory location; they can happen at the same time; and that there is nothing in the program to prevent it. This is different from a race condition , which is when you just don't know the order in which two actions are going to occur. I've put more discussion of what a data race actually is at the bottom of this post. A lot of people think that it is okay to have a data...