Reputation: 51761
I have an application where the memory profile looks something like this:
(source: kupio.com)
The slow upwards crawl of memory usage is caused by the allocation of lots and lots of small, simple, transient objects. In low-memory situations (This is a mobile app) the GC overhead is noticeable when compared to less restrictive memory amounts.
Since we know, due to the nature of the app, that these spikes will just keep on coming, I was considering some sort of pool of multitudinous transient objects (Awesome name). These objects would live for the lifetime of the app and be re-used wherever possible (Where the lifetime of the object is short and highly predictable).
Hopefully this would mitigate against the effects of GC by reducing the number of objects collected and improve performance.
Obviously this would also have its own performance limits since "allocation" would be more expensive and there would be an overhead in maintaining the cache itself.
Since this would be a rather large and intrusive change into a large amount of code, I was wondering if anyone had tried something similar and if it was a benefit, or if there were any other known ways of mitigating against GC in this sort of situation. Ideas for efficient ways to manage a cache of re-usable objects are also welcome.
Upvotes: 11
Views: 534
Reputation: 403471
Normally, I'd say this was a job for tuning the GC parameters of the VM, the reduce the spiky-ness, but for mobile apps that isn't really an option. So if the JVms you are using cannot have their GC behavioure modified, then old-fashioned object pooling may be the best solution.
The Apache Commons Pool library is good for that, although if this is a mobile app, then you may not want the library dependency overhead.
Upvotes: 2
Reputation: 6409
Check out this link. In particular:
Just to list a few of the problems object pools create: first, an unused object takes up memory space for no reason; the GC must process the unused objects as well, detaining it on useless objects for no reason; and in order to fetch an object from the object pool a synchronization is usually required which is much slower than the asynchronous allocation available natively.
Upvotes: 1
Reputation: 21186
Does J2ME have a generational garbage collector? If so it does many small, fast, collections and thus the pauses are reduced. You could try reducing the eden memory space (the small memory space) to increase the frequency and reduce the latency for collections and thus reduce the pauses.
Although, come to think of it, my guess is that you can't adjust gc behaviour because everything probably runs in the same VM (just a guess here).
Upvotes: 2
Reputation: 718778
Actually, that graph looks pretty healthy to me. The GC is reclaiming lots of objects and the memory is then returning to the same base level. Empirically, this means that the GC is working efficiently.
The problem with object pooling is that it makes your app slower, more complicated and potentially more buggy. What is more, it can actually make each GC run take longer. (All of the "idle" objects in the pool are non-garbage and need to be marked, etc by the GC.)
Upvotes: 2
Reputation: 54695
You could check out this link describing enhancements to the Concurrent Mark Sweep collector, although I'm not sure it's available for J2ME. In particular note:
"The concurrent mark sweep collector, also known as the concurrent collector or CMS, is targeted at applications that are sensitive to garbage collection pauses."
... "In JDK 6, the CMS collector can optionally perform these collections concurrently, to avoid a lengthy pause in response to a System.gc() or Runtime.getRuntime().gc() call. To enable this feature, add the option"
-XX:+ExplicitGCInvokesConcurrent
Upvotes: 1
Reputation: 134270
This is similar to the flyweight pattern detailed in the GoF patterns book (see edit below). Object pools have gone out of favour in a "normal" virtual machine due to the advances made in reducing the object creation, synchronization and GC overhead. However, these have certainly been around for a long time and it's certainly fine to try them to see if they help!
Certainly Object Pools are still in use for objects which have a very expensive creation overhead when compared with the pooling overheads mentioned above (database connections being one obvious example).
Only a test will tell you whether the pooling approach works for you on your target platforms!
EDIT - I took the OP "re-used wherever possible" to mean that the objects were immutable. Of course this might not be the case and the flyweight pattern is really about immutable objects being shared (Enum
s being one example of a flyweight). A mutable (read: unshareable) object is not a candidate for the flyweight pattern but is (of course) for an object pool.
Upvotes: 7
Reputation: 29119
Given that this answer suggests that there is not much scope for tweaking garbage collection itself in J2ME then if GC is an issue the only other option is to look at how you can change your application to improve performance/memory usage. Maybe some of the suggestions in the answer referenced would apply to your application.
As oxbow_lakes says, what you suggest is a standard design pattern. However, as with any optimisation the only way to really know how much it will improve your particular application is by implementing and profiling.
Upvotes: 0
Reputation: 391846
You're talking about a pool of reusable object instances.
class MyObjectPool {
List<MyObject> free= new LinkedList<MyObject>();
List<MyObject> inuse= new LinkedList<MyObject>();
public MyObjectPool(int poolsize) {
for( int i= 0; i != poolsize; ++i ) {
MyObject obj= new MyObject();
free.add( obj );
}
}
pubic makeNewObject( ) {
if( free.size() == 0 ) {
MyObject obj= new MyObject();
free.add( obj );
}
MyObject next= free.remove(0);
inuse.add( next );
return next;
}
public freeObject( MyObject obj ) {
inuse.remove( obj );
free.add( obj );
}
}
return in
Upvotes: 0