Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am very familiar with the concept of object pooling and I always try to use it as much as possible.

Additionally I always thought that object pooling is the standard norm as I have observed that Java itself as well as the other frameworks use pooling as much as possible.

Recently though I read something that was completely new (and counter-intuitive?) to me.

That pooling actually makes program performance worse especially in concurrent applications, and it is advisable to instantiate new objects instead, since in newer JVMs, instantiation of an object is really fast.

I read this in the book: Java Concurrency in Practice

Now I am starting to think if I am missunderstanding something here since the first part of the book adviced to use Executors that reuse Threads instead of creating new instances.

So has object pooling become deprecated nowadays?

share|improve this question
up vote 52 down vote accepted

It is deprecated as a general technique, because - as you noticed - creation and destruction of short lived objects per se (i.e. memory allocation and GC) is extremely cheap in modern JVMs. So using a hand-written object pool for your run-of-the-mill objects is most likely slower, more complicated and more error-prone than plain new.*

It still has its uses though, for special objects whose creation is relatively costly, like DB / network connections, threads etc.

*Once I had to improve the performance of a crawling Java app. Investigation uncovered an attempt to use an object pool to allocate millions of objects... and the clever guy who wrote it used a single global lock to make it thread safe. Replacing the pool with plain new made the app 30 times faster.

share|improve this answer
1  
So how can one decide if the instantiation of an object is too expensive? – user10326 Oct 19 '11 at 16:20
3  
If the object consumes operating system resources (threads, I/O, shared memory, etc.) – kevin cline Oct 19 '11 at 16:22
12  
@user10326, by measurement :-) If creating your objects takes a looooong time, and/or they are associated with some special, potentially limited, non-memory resource, you may consider pooling. – Péter Török Oct 19 '11 at 16:25
8  
@user10326, IMO in over 95% of cases, the above criteria makes it easy to decide in advance whether you need an object pool. (Moreover, in almost all of the cases needing a pool, you will most likely use an existing library/framework, which probably has the object pool already implemented for you.) For the rest, it is still easy to hide object creation in e.g. a factory, which can be later reimplemented whichever way you see fit. – Péter Török Oct 19 '11 at 16:38
2  
Very important point made by @Peter Torok: many frameworks and libraries implement pooling for you, ALWAYS make sure that you are not already using a pooled library before implementing your own. – hromanko Oct 19 '11 at 18:12

The answer to the concrete question: 'Is object pooling a deprecated technique?' is:

No. Object pooling is widely used in specific places - thread pooling, database connection pooling etc.

General object creation has never been a slow process. Pooling in itself consumes resources - memory and processing power. Any optimization is a trade-off.

The rule is:

Premature Optimization is Evil!!!

But when is a given optimization premature?

Premature optimization is any optimization done, before you have uncovered a bottleneck via thorough profiling.

share|improve this answer
2  
Indeed. OP said "I always try to use it as much as possible" - this is the problem, IMO. – nerdytenor Oct 20 '11 at 19:52
    
@Boris, So according to your second sentence, we should not object pool db connections and threads until we uncover them as a bottleneck via profiling? – Pacerier May 10 '14 at 8:06
1  
@Pac Some profiling results don't need constant re-measuring :-) – David Bullock Aug 28 '15 at 2:48

Measure

It completely depends on your use case, size of your objects, your JVM, your JVM options, what GC you have enabled and a whole host of other factors.

In short: measure it before and measure it after. Assuming you're using an object pooling framework (like from Apache) then it shouldn't be too painful to swap between implementations.

Extra performance testing tip - let the JVM warm up a bit first, run the tests on a running JVM a number of times, it can behave differently.

share|improve this answer
3  
"let the JVM warm up a bit first," -- I remember when the only thing that had to be "warmed up" was the monitor. Oy, everything new is old again. – kylben Oct 19 '11 at 16:53
    
The only thing I need to warm up is the coffee! – Craig Young Sep 23 '13 at 22:26
    
@Marijn, How do you let it "warm up"? – Pacerier May 10 '14 at 8:07
    
See the JMH Framework for a full explanation (openjdk.java.net/projects/code-tools/jmh) but basically you've got to give the JVM a chance to JIT your code, run GC's before your benchmark & so on. – Martijn Verburg May 12 '14 at 7:54

I do not know if there is a changing trend here but its certainly going to be the case that it depends. If your Java class is managing an external resource, such as an RMI connection or loading a resource file etc - then certainly the costs for object instantiation can still be high (though those resources may be pooled for you already!). As a general practice I'd agree with the book.

share|improve this answer
    
Well now I don't know.Because even in this case you describe which (before reading this) I would definetely use pooling, I would also have overhead.1)New constructs to handle the pooling 2) Synchronization for the getting/releasing object from pool 3) maintaining pool etc. So I am now thinking that perhaps there is no use case that it is useful except e.g. caching a socket instead of opening a new one each time to connect to the server.And this case is because of network latency and not instantiation creation overhead – user10326 Oct 19 '11 at 16:26
    
@user10326 Yes exactly. I see opening a socket as part of instantiation overhead, if its the class's job to do that and it must be initialized in the constructor then the latency & IO impacts are what you are concerned with. – Jeremy Oct 19 '11 at 16:28

In situations where you want to avoid garbage collection entirely, I think object pooling is the only viable alternative. So no, it is absolutely not a deprecated technique.

share|improve this answer
    
And I would add that it is a good idea to avoid GC whenever the objects are long-lived enough that they've moved into the older generation. – Zan Lynx Oct 19 '11 at 23:54

That pooling actually makes program performance worse especially in concurrent applications, and it is advisable to instantiate new objects instead, since in newer JVMs, instantiation of an object is really fast.

My knowledge of how the internal garbage collector works in Java is limited, but I've been reading papers lately that shed some light on the subject.

The way Java allocates objects initially uses a strategy similar to a sequential memory pool. Sequential pool allocators tend to be extremely fast at a rapid burst allocation strategy of objects. For example, in C, one can often see anywhere from a 2x to 10x improvement in constructing a complex tree if the nodes are allocated using a sequential allocator rather than a general allocator (malloc).

That's the initial phase of allocation against the Java GC. It's very fast for rapid allocation of objects, possibly even getting close to rivaling stack allocation of objects in languages like C++ and very-possibly even beating naive attempts to call operator new or malloc per object in such languages without an efficient memory pool involved (fixed allocator, sequential allocator, etc).

The second phase is a bit more complex. After a single GC cycle of this kind of rapid, sequentially-allocated memory, the GC moves (copies) the memory contents of objects still referenced to a more persistent region of memory. This part is a bit of a performance gotcha, since performance-critical fields often need to focus on concepts like spatial locality which ends up becoming lost if the memory contents of objects allocated together are then shuffled and dispersed in memory by a garbage collection cycle.

Object Pools

What does the above imply as far as object pools go? If the idea of using an object pool revolves around:

  1. Trying to allocate rapid bursts of objects faster, then it's very likely to actually contradict those goals and do more harm than good.
  2. Trying to improve spatial locality, then it's next to useless since the garbage collector will still rearrange the memory contents after an initial GC cycle for objects that survive (are still referenced) after one collection cycle.
  3. Trying to improve temporal locality in subsequent accesses, maybe it has some dim chance of improving read/write performance in critical loops for more complex objects.
  4. Trying to improve deterministic response/latency at the cost of throughput, then it might have some glimmer of a chance (ex: avoiding jarring stutters in frame rates in a video game but with the acknowledgement that the overall frame rate might get slower as a result of the pool even if the frame rate becomes more consistent/stable).
  5. Trying to reuse higher-level resource concepts and not the idea of the barebones object's memory (covered later), then it might have a good chance of helping.

Resource Pools

I'd distinguish "resource pools" from "object pools". For example, threads are very expensive to create in many operating systems (at the native level). A lot of libraries which distribute tasks repeatedly for various threads to process often use thread pools to avoid repeatedly paying the cost of creating and destroying threads.

While probably most Java developers wouldn't use a native thread API for this sort of thinking, imagine a scenario where they do. In that case, perhaps a thread is still modeled as an object.

Here using a thread pool is likely to help (which is pooling objects, but not for the typical reason of naively trying to avoid GC overhead). The pool here is not serving to avoid barebones object allocation/deallocation costs, but instead to avoid repeatedly initializing and destroying threads through the operating system.

In these cases where the resources associated to an object are very expensive to acquire (create) and release (destroy), then "object pools" might help a lot. Yet I wouldn't call them "object pools" anymore, since they're trying to resume using existing resources/states instead of trying to acquire a fresh object.

Data-Oriented Design

I often find myself citing data-oriented design as a solution to many performance-critical problems people encounter, but often I see people using object pools in areas like Java games when they will make their life a whole lot simpler and also get genuine, hard improvements in performance by applying data-oriented design instead.

Take this example:

class Particle
{
    ...
    private float size;
    private float x;
    private float y;
    private float z;
}

Someone might be tempted to pool this kind of Particle object as particles are born and die every few frames of a video game. An object pool is very unlikely to help here while making the code really dirty and harder to maintain.

Yet the real problem here is that the object-oriented design is being applied at too granular of a level. This translates to definite costs. For example, the size of a particle becomes 24 bytes instead of 16 in such a scenario, leading to more cache misses even in the lucky chance that multiple particles are right next to each other in memory and accessed prior to eviction. Yet any guarantees about spatial locality is effectively lost (we have no guarantees whatsoever that multiple particles will ever be anywhere close to each other in memory).

Instead by doing this:

class ParticleSystem
{
    ...
    private float[] xyzs = new float[n*4];
}

... we now have a contiguous AoS-style representation which has guaranteed spatial locality from one particle to the next, and no complex dynamics with temporal locality after an initial collection cycle. The size of each particle (at least ones that are accessed -- we might allocate more than necessary using chained pools of floating-point arrays) likewise shrinks down to 16 bytes, and more relevant particles then end up fitting into a 64-byte cache line (4 particles at once). An alternative to allow particles to be added and removed without an anticipated size in advance can be like this:

class ParticleSystem
{
    // How we represent things here doesn't matter so much. More
    // important is that we are designing our interfaces in a way
    // that leaves us room to change the underlying representation of
    // a collection of particles all we like.
    class ParticlePool
    {
        // has room for 128 particles.
        float[] xyzs = new float[128*4];

        // indicates whether a particle is used (can be tighter
        // using bits).
        boolean[] occupied = new boolean[128];

        // reference to next pool (initially null).
        ParticlePool next;
    }
    ...
    // Can use an array list with modulo 128 instead of singly-linked 
    // unrolled-style list if random-access is desired, can keep a list 
    // of free indices, etc. etc. etc. Most importantly, we can play with
    // this underlying representation all we like without breaking dependencies
    // to a ParticleSystem's public interface.
    private ParticlePool head = new ParticlePool;
}

This is not an object pool per se, but a "data" pool of plain old data represented contiguously through an array. It's almost certainly going to help if there's a heavy load here (ex: millions of particles being repeatedly accessed sequentially in critical loops). It's one possible strategy to optimize when dealing with a heavy load without reaching around the objects and trying to pool them individually.

If performance is a goal in cases where the barebones-style object pooling (not resource pooling) is a temptation, I'd suggest applying a data-oriented mindset. Design bulkier interfaces and objects, and you won't be trapped in a memory bottleneck interface design corner since your interfaces will give you a all the breathing room you need to iterate towards more efficient solutions like this.

Another example is to design Image interfaces instead of Pixel interfaces. If you have a million simple People entities you access in loops, design a People collection interface instead of a Person, e.g. This kind of data-oriented design approach will leave the breathing room you need to do all the optimization you need at the implementation level without breaking your designs, and without trying to pool little teeny objects.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.