SpatialPool?

As I'm sure is typical in many game development projects I am finding short-lived scene elements that I need to be able to re-use in my game (such as missile fire, lasers, ships, etc).  Obviously creating a new spatial every time I fire a weapon is a bad idea and would lead to massive performance issues not to mention to memory allocation horrors.



So I'm building a pooling system that manages spatials that can be retrieved and then returned when they are no longer needed to be re-used later.  My question is, is there already a mechanism for doing this that I'm not seeing?



Also, does anyone else see this as a beneficial feature to add to jME that could be re-used?

Okay, I got impatient so I went ahead and wrote a preliminary version and checked it in.



It exists in com.jmex.pool.SpatialPool.  I've also created a default generator called ByteArraySpatialGenerator that gets instantiated with a byte[] and essentially is a cloner.



It supports growing, non-blocking, erroring on max size being reached.  I haven't implemented the blocking aspect of it yet, but I will get around to that soon.



You can specify if you want it to pre-allocate the objects or allocate them as needed.



Insights and feedback welcome. :wink:

I think this is useful and builds upon a well known and established concept.  I had concerns over the very same thing for my Hexagons (if you've been following that thread) that I would use to overlay a map to show possible movement, range finding, firing arcs, etc.  I didn't want to constantly be creating them from scratch every time.

Pretty nice for objects that are used a lot, but still have are relativly big in size or need lot's of instancing.



I can't help the feeling though, that there has to be a better way to do this with Java. What I don't like is having to remember to "return" objects to the pool. Not having to care if you ever "free" the object you made, or if you "free' it one too many times (that could definatly be a problem here) is one of the reasons why I use Java and not C++.



I think you can avoid this by creating WeakReference to the object from the pool when you "hand out" the object. Then, for example once per frame, poll the ReferenceQueue you have put the WeakReference on. When you get a WeakReference back, it means it's associated object is no longer used by you, so you can put it back in the pool.



This of course will be slightly slower than the current implementation, but imho with pooling you can only make real gains if you're pooling objects with a high allocation cost… compared to that creating/destroying one small WeakReference object is very cheap.



edit: looking a bit through df's code, I can see this will be faster for sure, since now (to avoid the double releases and such) he's looping through the ArrayList… (probably to return the boolean wether it was succesful, and avoid double releases and the like). I guess you didn't use a HashMap because it creates/destorys object itself? (a lot more than one WeakReference too btw).

Hm, I don't have (decent) internet at my new home yet… but for the first time in months I do have some time! I'll probably take a stab at implementing this… however not sure when I can check it in… (next monday at work (yes I should be working right now) for sure though).

I'm fine with you tweaking it.  I considered using WeakReferences instead, but figured that using an ArrayList would keep new objects from being created and keep the garbage level down (particularly if you're potentially grabbing and releasing hundreds every few seconds as might be the case in a game uses it for weapon fire).  So long as it scales well and reduces the time to get an object you can do with it what you want. :wink:



Nice to see you're getting a little bit of time to work on fun stuff again…welcome back.  :slight_smile:

Hm, well I don't think creating an object when you need an object (and having it gc'ed when you're done with it) is necisarly bad, as long as it's a very cheap object to create. (Probably in many cases it will be faster than retrieving them from a pool and putting them back in).



For example, Creating 100s of WeakReferences will still beat the hell out of creating 100s of SharedMeshes… let alone 100s of Boxes or something like that. GCing is a lot faster too, since essentially WeakReferences are collected as shortlived objects (like creating an object within the scope of a single method). If you have hunderds of object, then looping through the entire array list (like in your code) when you release the object won't exactly be very… fast either. (could be resolved by tracking the state of your object by storing a "usage" flag in the object itself, but then they'd all have to implement this)



Another advantage of WeakReferences: they're slighty more friendly to multithreading (returning the objects into the pool can all be done from the same thread).

Good points.  Another concern I had with WeakReference is that the object wouldn't be returned to the pool until garbage collection was being run would it?



Say for example you are in a game with ten people firing missiles at each other and the number of missiles on screen at a time is 20 (two per person).  Well, as soon as those missiles explode and are removed from the scene are they returned to the pool or could it potentially be a while before that gets hit?  My concern is that the pool would end up making many more objects than would otherwise be necessary because it's taking too long for the object to be returned to the pool.

That is a concern, yes. I think you'd need a very special situation though where you'd get a really huge difference here. (I guess with smaller numbers the difference as a percentage would be the biggest).



In any case the weak reference thing would be optional.

Personally I think we should decide one way and go with it.  I don't like the idea of supporting two ideas that differentiate so much in implementation (the fact that release would have to be called on one and not on the other).



Go ahead and implement the WeakReference idea and I can try to do some testing to create lots of objects and then lose there reference and see how long it takes for them to end up back into the pool.

Using a non-blocking Queue instead of List will get rid of all the list iteration. Something like this for the get method:



T spatial = spatials.poll();
if (spatial != null) {
    inUse.add(spatial); // not actually necessary unless you want to have access to in-use instances, a ref-count would work for size tracking
    return spatial;
}

// pool is dry, create a new instance, return null, throw an exception, etc etc
...



and for release:


    inUse.remove(spatial); // again, not really necessary, can just use a ref counter
   spatials.offer(spatial);



I think WeakReference could be for when you don't care if a few more objects are created, and manual returns to a pool are for when even one or two addition constructions are going to be a significant hit.

If you want I could take a shot at a Queue implementation, but is there some test code that exists so I could make sure it's working the same?

Good call lazlohf!



I don't know why I didn't do that…I've actually done that exact thing in other pooling systems I've done before…  :?



ConcurrentLinkedQueue sufficient you think?

darkfrog said:

Good call lazlohf!

I don't know why I didn't do that....I've actually done that exact thing in other pooling systems I've done before...  :?

ConcurrentLinkedQueue sufficient you think?


Yeppers, ConcurrentLinkedQueue should give you what you need and eliminate the need for any synchronized blocks. I scanned the javadocs for it quickly, make sure to avoid a .size() call, that one could be a big hit.

Side note: I noticed you had a double-checked locking:


if (spatials.size() < size) {   // We haven't reached the max size yet, so we simply add one
   synchronized(spatials) {
      if (spatials.size() < size) {



That actually doesn't work due to how threading works with memory barriers (so the VM knows what must be synced between system memory and multiple CPU/core cache, etc, and order of operations performs correctly after optimization). There's an ok article on the issue but I found way more information in the uber-java-threading book "Java Concurrency in Practice" by Brian Goetz (ISBN 0321349601). If you work with multithreading, get or borrow a copy of this book :)

You might want to generalize this to a factory with methods to get common cached instances of game resources. Then it could do spatials, an (for ex) inputStreams by wrapping them in a bufferedInputStream, textures etc.



The problem is offcourse to extract the common part from the code configuration on each game, so its not really a factory, but a more general pool  (that could be encapsulated in game specific factories, etc).

I had considered just making it an ObjectPool that could be used instead…that would probably not be a bad idea as I could see situations where you might want to use it for other things…there's nothing specific to jME really here.

darkfrog said:

I had considered just making it an ObjectPool that could be used instead....that would probably not be a bad idea as I could see situations where you might want to use it for other things...there's nothing specific to jME really here.


What's cool is your current class just needs to be renamed and a few variable names since you've already used generics :) I'm not far enough in my game's dev, but I'm pretty sure I will need pools just as you guys do for missiles, etc.

Well, in that case, maybe you can just use the Pool component from the Jarkarta Commons project : http://jakarta.apache.org/commons/pool/

(several implementations of the interfaces are included)

I HATE Apache Commons project…also to use anything in the commons you end up with dependencies from one commons jar to another until you’ve practically got the whole freakin’ thing in your project.  :stuck_out_tongue:



I hated it so much I wrote my own alternative…their idea was good but most of their implementations are crappy…er, I mean…leave a lot to be desired. :o



http://jcommon.dev.java.net

The Librarian said:

Well, in that case, maybe you can just use the Pool component from the Jarkarta Commons project : http://jakarta.apache.org/commons/pool/
(several implementations of the interfaces are included)


I've used the Apache Commons quite a bit, but the main thing most of it doesn't provide is generics/java 1.5 support (I believe they maintain 1.3 and sometimes 1.1 compatibility). I'm a big fan of compile-time checks that can be enforced with generics as opposed to casting objects.

darkfrog said:

I HATE Apache Commons project.....also to use anything in the commons you end up with dependencies from one commons jar to another until you've practically got the whole freakin' thing in your project.  :P

I hated it so much I wrote my own alternative....their idea was good but most of their implementations are crappy....er, I mean....leave a lot to be desired. :o

http://jcommon.dev.java.net


:-o  It is true about the dependencies...currently my game doesn't include any Commons jars but most of the business apps I've written use them. *hides jars away from attack frogs*

I have situations with "business development" where I'm FORCED to use them, but unless I'm maintaining someone's crappy legacy application I'll opt out of dealing with the hideousness that is the majority of Apache's projects. :wink:



However, I will grant that Ant and Tomcat I use very frequently…not saying they're great, they're just better than the alternatives in my opinion.  :stuck_out_tongue: