Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2007

Tip: Looking for answers? Try searching our database.

Does object pooling *ever* make sense?

Thread view: 
Chris - 08 Feb 2007 00:53 GMT
I've read recently that object allocation in recent JVMs is so fast that
it doesn't make sense to create object pools. Just create a new object
when you need it and let the garbage collector do the work.

Does this hold true when your objects are very large, though? What if
your object contains a byte [] of length 100K? Or 1Mb?

What's the breakeven point beyond which it makes sense to reuse objects?
Lew - 08 Feb 2007 03:17 GMT
> I've read recently that object allocation in recent JVMs is so fast that
> it doesn't make sense to create object pools. Just create a new object
[quoted text clipped - 4 lines]
>
> What's the breakeven point beyond which it makes sense to reuse objects?

As I understand, the memory allocation procedure in the JVM is to add some
size n to a pointer p and call that region the new object. I don't think there
is anything much faster than that. It takes the same amount of time to add 10M
to p as to add 10. (<=1 cycle?)

The time spent is zeroing the memory, I'd guess, but you'd have to do that
with an object pool, too.

I surmise that there is no breakeven point.

- Lew
Daniel Pitts - 08 Feb 2007 04:06 GMT
> > I've read recently that object allocation in recent JVMs is so fast that
> > it doesn't make sense to create object pools. Just create a new object
[quoted text clipped - 16 lines]
>
> - Lew

I'd suggest running a few tests to find out.

The best suggestion I can make is to wrap all your calls to "new" in a
method somewhere, so that if you decide you need to pool, you can.

Generally, its bad engineering to worry about speed before it becomes
a problem. The first priority is clarity.  Next to functionality of
course.
If you find that there is a speed (or memory) issue, THEN you run a
profiler (don't ever "guess" or speculate on what the problem is,
you'll most likely be wrong, no matter how good you are)

The profiler will tell you what you need to optimize.

Hope this helps.
Gordon Beaton - 08 Feb 2007 07:50 GMT
> I've read recently that object allocation in recent JVMs is so fast
> that it doesn't make sense to create object pools. Just create a new
[quoted text clipped - 5 lines]
> What's the breakeven point beyond which it makes sense to reuse
> objects?

A disadvantage to pooling is that it increases the average age of your
objects, resulting in more live objects at any given time, more
objects that live beyond the "nursery", and consequently more work for
the garbage collector.

You also have to manage the object pool.

So in order for pooling to be effective, there has to be a saving
somewhere that outweighs these costs (and possibly others I haven't
mentioned). I don't think the cost depends as much on the *size* of
the object as it depends on the amount of additional *initialization*
that you need to do before you can use it, assuming that you can avoid
that initialization in the pooled case.

/gordon

Signature

[ don't email me support questions or followups ]
g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

Andreas Leitgeb - 08 Feb 2007 08:25 GMT
> Does this hold true when your objects are very large, though? What if
> your object contains a byte [] of length 100K? Or 1Mb?

If you can reuse the byte array without resetting it to zeros
(e.g. if the programs logic is such that every element of
the byte-array is overwritten, anyway) then it is possible
that pooling saves some time, but you take the risk that some
(otherwise minor) bug in your program might turn into nightmare
when old (non-zero) garbage in the array might slip through.
Andy Dingley - 08 Feb 2007 10:37 GMT
> I've read recently that object allocation in recent JVMs is so fast that
> it doesn't make sense to create object pools.

Most of my pooled objects are some sort of reference to an external
resource (e.g. a DB connection) that's inherently expensive. I don't
care what the cost of the object itself is, they're pooled to
economise on this external cost and that's not changed by any JVM
improvement.

Given the low cost of Java object creation I find it hard to justify
pooling for objects that are simply entirely Java anyway. What might
cause me to want to pool them?  A stateless singleton is justifiable
but anything with state attached to it probably means as much effort
to create the distinct state for each pooled use of the object as it
does to create a whole new object.
Lew - 08 Feb 2007 13:01 GMT
Chris <spam_me_...@goaway.com> wrote:
>> I've read recently that object allocation in recent JVMs is so fast that
>> it doesn't make sense to create object pools.

> Most of my pooled objects are some sort of reference to an external
> resource (e.g. a DB connection) that's inherently expensive. I don't
[quoted text clipped - 8 lines]
> to create the distinct state for each pooled use of the object as it
> does to create a whole new object.

And remember Gordon's points:

Gordon Beaton wrote:
>> A disadvantage to pooling is that it increases the average age of your
>> objects, resulting in more live objects at any given time, more
>> objects that live beyond the "nursery", and consequently more work for
>> the garbage collector.
>>
>> You also have to manage the object pool.

That "more work for the garbage collector" relates to the fact that it's
harder to garbage collect out of the tenured generation than the nursery.
Except for resource gates, it rarely helps to pool.

- Lew
Andy Dingley - 08 Feb 2007 15:30 GMT
> Except for resource gates, it rarely helps to pool.

One somewhat perverse use I have found for object pooling is to avoid
memory leakage. In a context of refactoring truly nasty code, a pool
of re-used objects was one way to avoid coders allocating these things
willy-nilly and never disposing of them afterwards at all!  Finite
cruft is (marginally) better than inifinite expanding cruft.

...And it's less cruel than my other technique, with the hot clueiron.
Lew - 09 Feb 2007 00:43 GMT
> One somewhat perverse use I have found for object pooling is to avoid
> memory leakage. In a context of refactoring truly nasty code, a pool
[quoted text clipped - 3 lines]
>
> ...And it's less cruel than my other technique, with the hot clueiron.

Of course, in Java one does not often have to explicitly "dispose of" an
object. The usual difficulty is making sure to pull all references away from
an object, but there are a huge number of situations where that isn't necessary.

Consider:

public void foo()
{
   Bax bax = new Bax(); // assume it does not wrap a resource
  // do some stuff with bax
  // but do NOT create other references to the object
}

No explicit disposal needed for the new Bax if it is never referenced
somewhere else, e.g., in a long-lived Collection. Once the variable "bax" goes
out of scope in that scenario, the programmer can rest easy.

It is actually a good idiom in Java to "allocat[e] ... things willy-nilly".

- Lew
Andy Dingley - 09 Feb 2007 12:25 GMT
> Of course, in Java one does not often have to explicitly "dispose of" an object.

One certainly must if it's not garbage collectable!

A problem with Java in general, particularly with newbie coders who've
only learned Java from scratch, is that they pay no attention to gc at
all and just assume that "the maid will clear it up". This works fine
for most pure Java objects, but if you start having some object that
represents another resource and isn't automatically disposable then
you're back to needing to manage these manually (at least to some
degree). Leaving it up to Java's gc means that none of them ever get
disposed, and you've a leak.

Languages that reduce the need to think about everything are great for
fast development, but when this extends into a mindset that no longer
thinks at all, it leads to sloppy development.
Lew - 09 Feb 2007 16:10 GMT
>> Of course, in Java one does not often have to explicitly "dispose of" an object.
>
[quoted text clipped - 8 lines]
> degree). Leaving it up to Java's gc means that none of them ever get
> disposed, and you've a leak.

I completely agree. Note that I disclaimed the case where an object manages an
external resource, but then in that case it is no longer a memory issue. The
original question had to do with memory allocation and deallocation overhead,
and in that context Java's mechanism is entirely satisfactory.

With regard to not thinking and assumptions about the maid's thoroughness you
have the right of it. Playing to the strengths of the Java model does not mean
ignoring it, it means understanding it so well that you can take advantage of it.

If you understand the memory model then, for example, you can exploit things
like the WeakReference class.

WRT external resources, Java gives one the finally block.

- Lew
buggy - 09 Feb 2007 23:40 GMT
>> I've read recently that object allocation in recent JVMs is so fast that
>> it doesn't make sense to create object pools.
[quoted text clipped - 4 lines]
> economise on this external cost and that's not changed by any JVM
> improvement.

Yes, but DB connection pooling is entirely different. There is a cost
associated with establishing a DB connection (logging in, creating a
pipe etc). A DB connection pool is vastly preferable (I use proxool).

Mind you ONLY the connection is pooled. All the other objects associated
with the DB call are created normally.
Joe Seigh - 09 Feb 2007 02:19 GMT
> I've read recently that object allocation in recent JVMs is so fast that
> it doesn't make sense to create object pools. Just create a new object
[quoted text clipped - 4 lines]
>
> What's the breakeven point beyond which it makes sense to reuse objects?

Not so much that the gc is so much faster than it's not really all that worse
and the effects of tying up a lot of memory in object pools is more problematic.
The copying collector relies on having enough memory so you don't run out
between normal GC cycles.  If you are running out of memory and forcing GC
to run more often, you could just use an object pool and use a WeakReference to
point to the object pool.  The pool will be reclaimed on every GC cycle more
or less.  The only time a pool will exist is when it's active.  I'm assuming
weak references don't slow down GC all that much.

Signature

Joe Seigh

When you get lemons, you make lemonade.
When you get hardware, you make software.

Lew - 09 Feb 2007 06:36 GMT
> Not so much that the gc is so much faster than it's not really all that
> worse
> and the effects of tying up a lot of memory in object pools is more
> problematic.

The Java mechanisms and GC tend to be much faster than hand-rolled object
pooling (except for resource guards, but then it's not memory that is the slow
part any more).

According to what I've read.

> The copying collector relies on having enough memory so you don't run out
> between normal GC cycles.  

What do you mean by "between normal GC cycles"? From what I've read, GC runs
when memory runs low, not on some kind of timer.

> If you are running out of memory and forcing GC to run more often,
> you could just use an object pool and use a WeakReference to
> point to the object pool.  The pool will be reclaimed on every GC cycle
> more or less.  The only time a pool will exist is when it's active.  I'm
> assuming weak references don't slow down GC all that much.

I have not run across any reference that ties weak references to any
performance considerations for garbage collection.

The point is that you do not need to use object pooling. The Java memory
allocator is more efficient, by all accounts, than any local policy can hope
to achieve, and using custom schemes is only likely to interfere with the Java
mechanism.

The whole point of the Java memory mechanism is to remove responsibility for
memory management from the programmer. Why would anyone want to mess with that?

If you want to tune the collector, that's an entirely different matter. You
are much more likely to gain joy from the java -X and -XX parameters than any
in-process approach.

There is a common theme running in this newsgroup of people not wanting Java
to be Java. This seems to blind them to the strengths of the language, as they
focus on perceived weaknesses. No language is perfect. Part of the art of
programming involves playing to the strengths of the tools at hand.

Java provides a lot of help with memory management. Use what it offers before
trying to defeat it.

- Lew
Joe Seigh - 09 Feb 2007 11:44 GMT
> The point is that you do not need to use object pooling. The Java memory
> allocator is more efficient, by all accounts, than any local policy can
> hope to achieve, and using custom schemes is only likely to interfere
> with the Java mechanism.

For most Java programmers, that is likely true.

> The whole point of the Java memory mechanism is to remove responsibility
> for memory management from the programmer. Why would anyone want to mess
> with that?

Well, I mess with a whole lot of things that people think can't be improved.
Some things can be improved by quite a bit (orders of magnitude).

Signature

Joe Seigh

When you get lemons, you make lemonade.
When you get hardware, you make software.

Chris Uppal - 09 Feb 2007 17:27 GMT
> What do you mean by "between normal GC cycles"? From what I've read, GC
> runs when memory runs low, not on some kind of timer.

Depends on the GC implementation.  There are algorithms which collect garbage
on a continuous basis.  And it's not an unreasonable technique, for VMs aimed
at desktop applications and the like, to run a low-priority GC task on a timer
(that's a VM implementation technique, mind, not a recommendation that desktop
/applications/ should be coded that way).

And in fact the Sun GC implementations, which use multiple spaces, don't really
have a concept of waiting until memory runs low before running GC.  They do
have a, comparatively expensive, "full" GC which is run if memory does run low,
but the object of the design is to avoid doing that as far as possible.
Ideally to eliminate it altogether.

   -- chris
Chris Uppal - 09 Feb 2007 16:18 GMT
> Does this hold true when your objects are very large, though? What if
> your object contains a byte [] of length 100K? Or 1Mb?

It is trivially true that object pooling /can/ make sense.  The lifetime cost
of an object is the sum of

   the time taken to allocate its store
   the time taken to zero that store
   the time taken in user-code initialising it
   the time take to reclaim that store

If you use object pooling then the equation changes to

   the time taken to reset the object's state
   the time take to manage the pool

So if an object can be "reset" faster than it could be
created+zeroed+initialised then you have a potential saving.  If that saving is
great enough to outweigh the costs described by other posters, then you are
making a nett profit.

But, it always possible (with sufficient ingenuity) to devise examples of
objects which take arbitrarily longer to initialise than to reset, so it is
always possible to devise examples of objects which would benefit from pooling.

Such examples don't often come up in real code, though.  It would probably
require that the object had an extremely complicated initial internal state but
one to which it could be returned comparatively cheaply.  (E.g. some
complicated pre-computed wordlist/dictionary).

Whether you can reach that position just by using larger and larger simple
arrays seems doubtful.  Allocating a single object, even a large one, is not an
expensive operation in itself.  It's difficult to imagine a scenario where the
initialisation (if any) of the array in user code was significantly cheaper
than resetting it.  So that leaves only the time taken by the VM to zero the
store as a potentially worthwhile saving.  That is obviously proportional to
the size of the array, so that's looking promising so far.  But consider the
overall life of the array -- presumably the code is going to do something with
it, so it seems almost certain that most positions in the array will be written
to, and read, at least once by the application code.  Both of those operations
will be at least as expensive as the initial zeroing (per slot), so the time
saved can be no more than 1/3 of the total runtime and, in realistic
applications, almost certainly much less -- which moves the potential saving
into the "it's not worth bothering with" category.

Of course, that last paragraph assumes that the VM/GC implementation is such
that it has no great difficulty with "churning" large objects -- that does
depend on the implementation.  It would be interesting to how the numbers work
out in practise rather than in theory[*].

   -- chris

[*] And please, don't anyone at this point produce that tired old cliché about
how "theory and practise are the same in theory [etc]"
Andy Dingley - 09 Feb 2007 18:00 GMT
On 9 Feb, 16:18, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
THIS.org> wrote:

> So if an object can be "reset" faster than it could be
> created+zeroed+initialised then you have a potential saving.

Of course. Except that zeroed+initialised is trivially fast,
management isn't and creation is usually pretty speedy too. Your
conclusion here is _far_ from guaranteed.

There's an equally over-simplifed proof that garbage collection is
just one form of pool management, so anything that overlays another
layer of pool management over any existing layer of pool management
_must_ be slower than just having a single layer.

It's all Melvyn Bragg's fault. I've been reading Popper this week and
now I can't believe _anything_ anyone tells me!
Chris Uppal - 09 Feb 2007 19:00 GMT
[me:]
> > So if an object can be "reset" faster than it could be
> > created+zeroed+initialised then you have a potential saving.
>
> Of course. Except that zeroed+initialised is trivially fast,
> management isn't and creation is usually pretty speedy too. Your
> conclusion here is _far_ from guaranteed.

I believe that you have misunderstood the whole of my post.

> It's all Melvyn Bragg's fault. I've been reading Popper this week and
> now I can't believe _anything_ anyone tells me!

Reading it seems to have damaged your ability to follow an argument too ;-)
Maybe your expectations are now set too high...

   -- chris
Chris - 09 Feb 2007 21:36 GMT
> I've read recently that object allocation in recent JVMs is so fast that
> it doesn't make sense to create object pools. Just create a new object
[quoted text clipped - 4 lines]
>
> What's the breakeven point beyond which it makes sense to reuse objects?

Thanks, everybody, for the insights, but nobody really shed any light on
the original question, which was: what's the breakeven point?

So I wrote a little code to test the question, pasted below. The code
simply allocates byte [] objects of varying sizes. Here are the results,
for 100,000 iterations, elapsed time in milliseconds:

bufsize 10 elapsed = 16
bufsize 1024 elapsed = 47
bufsize 10240 elapsed = 313
bufsize 102400 elapsed = 3078
bufsize 1048576 elapsed = 316540
bufsize 10Mb, terminated because it took too long

JDK 1.6, JVM memory = the default 64mb (increasing JVM memory did not
alter the results).

Contrary to some of the earlier advice in this thread, it is *not*
trivially fast to allocate larger objects. Allocation time increases
roughly linearly as object sizes increase.

Given that fetching an object from a pool 100,000 times should generally
not take more than a few milliseconds (locking & sync included), it
looks like object pooling is a necessity when speed is important and
objects get larger than a few dozen Kb in size.

public static void main(String[] argv) throws Exception {

// 10, 1K, 10K, 100K, 1Mb, 10Mb
int [] BUFSIZES = {10, 1024, 10 * 1024, 100 * 1024, 1024 * 1024, 10
*1024 * 1024};
  int ITERATIONS = 100000;

  for (int bufSizePtr = 0; bufSizePtr < BUFSIZES.length; bufSizePtr++) {
    int bufSize = BUFSIZES[bufSizePtr];
    long start = System.currentTimeMillis();
    for (int i = 0; i < ITERATIONS; i++) {
        byte[] buf = new byte [bufSize];
        buf[0] = 1;
      }
    long elapsed = System.currentTimeMillis() - start;
    System.out.println("bufsize " + bufSize + " elapsed = " + elapsed);
  }
}
Chris - 09 Feb 2007 21:48 GMT
> Contrary to some of the earlier advice in this thread, it is *not*
> trivially fast to allocate larger objects. Allocation time increases
> roughly linearly as object sizes increase.

Here's more evidence. The code was rewritten to use System.nanoTime()
and to double the amount of memory allocated on each cycle. Times are
still in millisec:

bufsize 1 elapsed = 61
bufsize 2 elapsed = 23
bufsize 4 elapsed = 22
bufsize 8 elapsed = 23
bufsize 16 elapsed = 24
bufsize 32 elapsed = 29
bufsize 64 elapsed = 41
bufsize 128 elapsed = 60
bufsize 256 elapsed = 107
bufsize 512 elapsed = 192
bufsize 1024 elapsed = 344
bufsize 2048 elapsed = 669
bufsize 4096 elapsed = 1308
bufsize 8192 elapsed = 2519
bufsize 16384 elapsed = 4970
bufsize 32768 elapsed = 9934
bufsize 65536 elapsed = 19732
bufsize 131072 elapsed = 39455
bufsize 262144 elapsed = 73419

For very small objects, allocation time is constant. As you get to
larger objects, allocation time doubles as you double the size. Above
~1K, allocation time is close to linear.

Same pattern applies for JDK 1.4, 1.5, and 1.6.
pascal.lecointe@euriware.fr - 09 Feb 2007 22:23 GMT
> > Contrary to some of the earlier advice in this thread, it is *not*
> > trivially fast to allocate larger objects. Allocation time increases
[quoted text clipped - 29 lines]
>
> Same pattern applies for JDK 1.4, 1.5, and 1.6.

It's probably the time needed to zero the array ... which is
proportional to the size of the array
Mark Rafn - 09 Feb 2007 23:35 GMT
>> What's the breakeven point beyond which it makes sense to reuse objects?
...
>Thanks, everybody, for the insights, but nobody really shed any light on
>the original question, which was: what's the breakeven point?

That's because there's no single breakeven point.  It depends on usage
patterns, VM implementation, underlying hardware/OS, and probably other
factors.

>So I wrote a little code to test the question, pasted below. The code
>simply allocates byte [] objects of varying sizes.

To be fair, it should compare that to finding and zeroing byte[] of the same
sizes.

>Given that fetching an object from a pool 100,000 times should generally
>not take more than a few milliseconds (locking & sync included),

No, but clearing it 100,000 times might take longer than allocating it 100,000
times, on some implementations.  And writing into the Nth byte could take
different amounts of time depending on how it's been used before.

>looks like object pooling is a necessity when speed is important and
>objects get larger than a few dozen Kb in size.

That's far too simplistic a statement.  It may be true where your usage
pattern is that you allocate a huge buffer, don't care what's initially in it,
only write to the first byte, never read from it, don't ever need different
ones at the same time, and are running on a specific platform.

That said, I'd agree that it's worth considering pooling for large objects
with a high amount of reuse, especially if they're immutable.
--
Mark Rafn    dagon@dagon.net    <http://www.dagon.net/>
Chris - 10 Feb 2007 01:26 GMT
>> looks like object pooling is a necessity when speed is important and
>> objects get larger than a few dozen Kb in size.
[quoted text clipped - 3 lines]
> only write to the first byte, never read from it, don't ever need different
> ones at the same time, and are running on a specific platform.

Here's new benchmark:

I created an array of 1000 128K buffers. This is enough to ensure that
most of them are in main memory, not the processor cache.

I ran Arrays.fill(buffer, (byte)0) on the list 100 times, for a total of
100,000 calls.

The elapsed time? 40 seconds, almost exactly the amount of time required
to allocate 100,000 128K buffers in the previous benchmark. This
indicates that zeroing the arrays probably does take up most of the
time when allocating new objects.

This does support my claim that object pooling is a necessity when using
large objects, *except* in cases where zeroing is necessary.

Which raises a question: wouldn't it be a good idea to have a way to
tell Java, in special cases, not to zero out allocated objects?
pascal.lecointe@euriware.fr - 10 Feb 2007 08:32 GMT
> >> looks like object pooling is a necessity when speed is important and
> >> objects get larger than a few dozen Kb in size.
[quoted text clipped - 22 lines]
> Which raises a question: wouldn't it be a good idea to have a way to
> tell Java, in special cases, not to zero out allocated objects?

And it make the case of pooling only useful for primitive array. For
reference arrays, you *must* zero the array when you pull it back in
the pool, otherwise the GC cannot collect the objects referenced by
the array (and bingo the memory leak :)).

And between different primitives, perhaps the time to zero is not the
same (problems of alignment to 32bits or 64bits), perhaps the time to
zero the same array of integer is less than with a byte array

So, it's useful to pool :
- when it's an array of primitives
- and when you don't have to zero the array when you take it from the
pool

And there is the problem of synchronization of the pool... to compare
you must execute the two options

I'll be back with a complete test :)
pascal.lecointe@euriware.fr - 10 Feb 2007 09:24 GMT
On 10 fév, 09:32, "pascal.lecoi...@euriware.fr"
<pascal.lecoi...@euriware.fr> wrote:

> > >> looks like object pooling is a necessity when speed is important and
> > >> objects get larger than a few dozen Kb in size.
[quoted text clipped - 41 lines]
>
> I'll be back with a complete test :)

<scce>
/**
* Test of the utility of pool for primitive arrays
*/
public class TestPool {

    public static final int ITERATIONS = 100000;
    public static final int NB_INCREMENTS = 19;

    public static void main(String[] args) {
        testByteWithPool();
        testByteWithoutPool();
        testIntWithPool();
        testIntWithoutPool();
    }

    /** An object to lock the pool when we use it */
    private static Object poolLock = new Object();
    private static boolean poolUsed = false;

    private static byte[] bytePool;
    private static int[] intPool;
    private static Object[] refPool;

    private static void testByteWithPool() {
        int currentSize = 1;

        for (int j = 0; j < NB_INCREMENTS; j++) {

            long t1 = System.nanoTime();
            // Creation of the pool
            synchronized (poolLock) {
                bytePool = new byte[currentSize];
                poolUsed = false;
            }
            for (int i = 0; i < ITERATIONS; i++) {
                byte[] array = null;
                // Get the array from pool
                synchronized (poolLock) {
                    if (poolUsed) {
                        throw new RuntimeException("pool already in use");
                    }
                    array = bytePool;
                    poolUsed = true;
                }
                // use the array
                array[0] = 1;
                // put back the array in the pool
                synchronized (poolLock) {
                    poolUsed = false;
                }
            }
            long t2 = System.nanoTime();
            System.out.printf("BYTE POOL : bufsize %d elapsed = %d\n",
currentSize, (t2-t1)/1000000);

            currentSize *= 2;
        }
    }

    private static void testByteWithoutPool() {
        int currentSize = 1;

        for (int j = 0; j < NB_INCREMENTS; j++) {

            long t1 = System.nanoTime();
            for (int i = 0; i < ITERATIONS; i++) {
                // Get the array
                byte[] array = new byte[currentSize];
                // use the array
                array[0] = 1;
            }
            long t2 = System.nanoTime();
            System.out.printf("BYTE NOPOOL : bufsize %d elapsed = %d\n",
currentSize, (t2-t1)/1000000);

            currentSize *= 2;
        }
    }

    private static void testIntWithPool() {
        int currentSize = 1;

        for (int j = 0; j < NB_INCREMENTS; j++) {

            long t1 = System.nanoTime();
            // Creation of the pool
            synchronized (poolLock) {
                intPool = new int[currentSize];
                poolUsed = false;
            }
            for (int i = 0; i < ITERATIONS; i++) {
                int[] array = null;
                // Get the array from pool
                synchronized (poolLock) {
                    if (poolUsed) {
                        throw new RuntimeException("pool already in use");
                    }
                    array = intPool;
                    poolUsed = true;
                }
                // use the array
                array[0] = 1;
                // put back the array in the pool
                synchronized (poolLock) {
                    poolUsed = false;
                }
            }
            long t2 = System.nanoTime();
            System.out.printf("INT POOL : bufsize %d elapsed = %d\n",
currentSize, (t2-t1)/1000000);

            currentSize *= 2;
        }
    }

    private static void testIntWithoutPool() {
        int currentSize = 1;

        for (int j = 0; j < NB_INCREMENTS; j++) {

            long t1 = System.nanoTime();
            for (int i = 0; i < ITERATIONS; i++) {
                // Get the array
                int[] array = new int[currentSize];
                // use the array
                array[0] = 1;
            }
            long t2 = System.nanoTime();
            System.out.printf("INT NOPOOL : bufsize %d elapsed = %d\n",
currentSize, (t2-t1)/1000000);

            currentSize *= 2;
        }
    }

}
</scce>

And the results are :

BYTE POOL : bufsize 1 elapsed = 8
BYTE POOL : bufsize 2 elapsed = 4
BYTE POOL : bufsize 4 elapsed = 4
BYTE POOL : bufsize 8 elapsed = 4
BYTE POOL : bufsize 16 elapsed = 3
BYTE POOL : bufsize 32 elapsed = 4
BYTE POOL : bufsize 64 elapsed = 4
BYTE POOL : bufsize 128 elapsed = 4
BYTE POOL : bufsize 256 elapsed = 1
BYTE POOL : bufsize 512 elapsed = 6
BYTE POOL : bufsize 1024 elapsed = 4
BYTE POOL : bufsize 2048 elapsed = 3
BYTE POOL : bufsize 4096 elapsed = 2
BYTE POOL : bufsize 8192 elapsed = 4
BYTE POOL : bufsize 16384 elapsed = 6
BYTE POOL : bufsize 32768 elapsed = 2
BYTE POOL : bufsize 65536 elapsed = 6
BYTE POOL : bufsize 131072 elapsed = 4
BYTE POOL : bufsize 262144 elapsed = 4
BYTE NOPOOL : bufsize 1 elapsed = 3
BYTE NOPOOL : bufsize 2 elapsed = 1
BYTE NOPOOL : bufsize 4 elapsed = 1
BYTE NOPOOL : bufsize 8 elapsed = 4
BYTE NOPOOL : bufsize 16 elapsed = 3
BYTE NOPOOL : bufsize 32 elapsed = 4
BYTE NOPOOL : bufsize 64 elapsed = 8
BYTE NOPOOL : bufsize 128 elapsed = 19
BYTE NOPOOL : bufsize 256 elapsed = 19
BYTE NOPOOL : bufsize 512 elapsed = 49
BYTE NOPOOL : bufsize 1024 elapsed = 80
BYTE NOPOOL : bufsize 2048 elapsed = 162
BYTE NOPOOL : bufsize 4096 elapsed = 308
BYTE NOPOOL : bufsize 8192 elapsed = 651
BYTE NOPOOL : bufsize 16384 elapsed = 1210
BYTE NOPOOL : bufsize 32768 elapsed = 2389
BYTE NOPOOL : bufsize 65536 elapsed = 4750
BYTE NOPOOL : bufsize 131072 elapsed = 9634
BYTE NOPOOL : bufsize 262144 elapsed = 19496
INT POOL : bufsize 1 elapsed = 6
INT POOL : bufsize 2 elapsed = 4
INT POOL : bufsize 4 elapsed = 4
INT POOL : bufsize 8 elapsed = 4
INT POOL : bufsize 16 elapsed = 6
INT POOL : bufsize 32 elapsed = 4
INT POOL : bufsize 64 elapsed = 4
INT POOL : bufsize 128 elapsed = 2
INT POOL : bufsize 256 elapsed = 4
INT POOL : bufsize 512 elapsed = 4
INT POOL : bufsize 1024 elapsed = 4
INT POOL : bufsize 2048 elapsed = 4
INT POOL : bufsize 4096 elapsed = 4
INT POOL : bufsize 8192 elapsed = 7
INT POOL : bufsize 16384 elapsed = 4
INT POOL : bufsize 32768 elapsed = 4
INT POOL : bufsize 65536 elapsed = 2
INT POOL : bufsize 131072 elapsed = 4
INT POOL : bufsize 262144 elapsed = 4
INT NOPOOL : bufsize 1 elapsed = 5
INT NOPOOL : bufsize 2 elapsed = 5
INT NOPOOL : bufsize 4 elapsed = 0
INT NOPOOL : bufsize 8 elapsed = 4
INT NOPOOL : bufsize 16 elapsed = 5
INT NOPOOL : bufsize 32 elapsed = 11
INT NOPOOL : bufsize 64 elapsed = 25
INT NOPOOL : bufsize 128 elapsed = 42
INT NOPOOL : bufsize 256 elapsed = 80
INT NOPOOL : bufsize 512 elapsed = 161
INT NOPOOL : bufsize 1024 elapsed = 306
INT NOPOOL : bufsize 2048 elapsed = 604
INT NOPOOL : bufsize 4096 elapsed = 1180
INT NOPOOL : bufsize 8192 elapsed = 2394
INT NOPOOL : bufsize 16384 elapsed = 4763
INT NOPOOL : bufsize 32768 elapsed = 9541
INT NOPOOL : bufsize 65536 elapsed = 18997
INT NOPOOL : bufsize 131072 elapsed = 38034
INT NOPOOL : bufsize 262144 elapsed = 76232

So we can conclude :
- using the pool for a primitive array is constant (but my pool is
very light, one object, the overhead of a real pool will be much
important)
- zeroing the array of int is four times zeroing the array of byte
- the time is very short, for an array of 256k, creating and
initializing an array if about 0.19 ms

so it really depends if the creation of array is really very intense
in your program

as always, profile first, optimize after :)
pascal.lecointe@euriware.fr - 10 Feb 2007 09:34 GMT
On 10 fév, 10:24, "pascal.lecoi...@euriware.fr"
<pascal.lecoi...@euriware.fr> wrote:
> On 10 fév, 09:32, "pascal.lecoi...@euriware.fr"
>
[quoted text clipped - 277 lines]
>
> as always, profile first, optimize after :)

I did the same test with zeroing the array when i take it from the
pool.

The results are :
BYTE POOL : bufsize 1 elapsed = 10
BYTE POOL : bufsize 2 elapsed = 9
BYTE POOL : bufsize 4 elapsed = 7
BYTE POOL : bufsize 8 elapsed = 8
BYTE POOL : bufsize 16 elapsed = 11
BYTE POOL : bufsize 32 elapsed = 13
BYTE POOL : bufsize 64 elapsed = 32
BYTE POOL : bufsize 128 elapsed = 45
BYTE POOL : bufsize 256 elapsed = 83
BYTE POOL : bufsize 512 elapsed = 158
BYTE POOL : bufsize 1024 elapsed = 314
BYTE POOL : bufsize 2048 elapsed = 620
BYTE POOL : bufsize 4096 elapsed = 1230
BYTE POOL : bufsize 8192 elapsed = 2470
BYTE POOL : bufsize 16384 elapsed = 4924
BYTE NOPOOL : bufsize 1 elapsed = 7
BYTE NOPOOL : bufsize 2 elapsed = 2
BYTE NOPOOL : bufsize 4 elapsed = 0
BYTE NOPOOL : bufsize 8 elapsed = 2
BYTE NOPOOL : bufsize 16 elapsed = 4
BYTE NOPOOL : bufsize 32 elapsed = 4
BYTE NOPOOL : bufsize 64 elapsed = 7
BYTE NOPOOL : bufsize 128 elapsed = 20
BYTE NOPOOL : bufsize 256 elapsed = 25
BYTE NOPOOL : bufsize 512 elapsed = 39
BYTE NOPOOL : bufsize 1024 elapsed = 82
BYTE NOPOOL : bufsize 2048 elapsed = 161
BYTE NOPOOL : bufsize 4096 elapsed = 308
BYTE NOPOOL : bufsize 8192 elapsed = 602
BYTE NOPOOL : bufsize 16384 elapsed = 1192
INT POOL : bufsize 1 elapsed = 9
INT POOL : bufsize 2 elapsed = 6
INT POOL : bufsize 4 elapsed = 6
INT POOL : bufsize 8 elapsed = 10
INT POOL : bufsize 16 elapsed = 13
INT POOL : bufsize 32 elapsed = 13
INT POOL : bufsize 64 elapsed = 21
INT POOL : bufsize 128 elapsed = 45
INT POOL : bufsize 256 elapsed = 84
INT POOL : bufsize 512 elapsed = 161
INT POOL : bufsize 1024 elapsed = 320
INT POOL : bufsize 2048 elapsed = 618
INT POOL : bufsize 4096 elapsed = 1252
INT POOL : bufsize 8192 elapsed = 2478
INT POOL : bufsize 16384 elapsed = 4953
INT NOPOOL : bufsize 1 elapsed = 5
INT NOPOOL : bufsize 2 elapsed = 1
INT NOPOOL : bufsize 4 elapsed = 2
INT NOPOOL : bufsize 8 elapsed = 6
INT NOPOOL : bufsize 16 elapsed = 6
INT NOPOOL : bufsize 32 elapsed = 7
INT NOPOOL : bufsize 64 elapsed = 24
INT NOPOOL : bufsize 128 elapsed = 39
INT NOPOOL : bufsize 256 elapsed = 82
INT NOPOOL : bufsize 512 elapsed = 152
INT NOPOOL : bufsize 1024 elapsed = 302
INT NOPOOL : bufsize 2048 elapsed = 617
INT NOPOOL : bufsize 4096 elapsed = 1201
INT NOPOOL : bufsize 8192 elapsed = 2399
INT NOPOOL : bufsize 16384 elapsed = 4790

The "manual" zeroing of the array of byte is four times the self
zeroing of the array (by the operator new)


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.