minimizing garbage collection

I do know how his code works, since he came on the forums and told everyone. But I guess some people have problems with this and some don’t.

I think what he means to say, and it’s been said before, is pool objects that are expensive to construct or destroy. So don’t bother pooling little crappy ones like Integers and Particles, it’s far more trouble than it’s worth.

Cas :slight_smile:

Cas, you already said that in that other thread:

You can hardly call this an expensive to initialize object:

public class Vec3 {
public float x,y,z;
}

Yet it slows down the application by factor 3, even if there are LOTS of other calculations doing on, so the benchmark is really not focusing on the allocation, but loses a large chunk of its performance anyway.

I don’t think you’d pool such objects though. What I do is I tend to make a


private static final Vector3f TEMP = new Vector3f();

somewhere in my class and use that over and over for intermediary operations. Not exactly pooling.

Cas :slight_smile:

So, I read the thread.

Im really not sure your testing what you think you are. Even if the code gets inlined from your method there are still questions of whether or not registers get used as efficiently.

Its really not a proper test because you have multiple variables (allocation and method call) and youa re just assuming that all the resulting imapct is from one of them

To test properly you would need to eliminate the other variants. In this case, it means writing an “add” mthod that uses pooled objects rather then a new.

Remember that Java allocations must return zeroed memory as far as your object’s constructor can tell anyway (any field not explicitly initialized will be set to 0 or null). That is likely the difference between using ‘new’ or fetching an old object from a pool. The old object doesn’t need to be cleared.

So, sure the allocation step can be just a pointer shift, but the initialization step must be accounted for.

(please excuse the resurrection of the thread)

In practise, as soon as you reuse an object from a pool you have to re-initialize all its fields anyway. So in the field, this will likely make such an unnoticeable difference it won’t matter.

Cas :slight_smile:

My point was that fields are initialized twice for allocation - first they are zeroed, then the constructor can put in the real values. For the object pool the previous values are only overwritten once with the new real values, the zeroing step is skipped.

Is this true for all circumstances? I was under the impression, that zeroing is skipped for directly initialized fields (e.g. private int foo=23;) and final fields initialized from the constructor…

Oh gosh, let me try to clear this up. There is an overhead to creating new objects and unfortunately this may not be tackled optimally for a long time to come - however there is potential for the JVM to better analyse the allocations. I created a simple benchmark with a mutable FixedInt class that is a weird hybrid between fixed and floating point. Basically the class allows for easy calculations involving integers with different fixed points automatically, however I found that the following type of loop was slower to a factor of 5 (for divides) and when replaced with the mutable type.


	private static void emptyInt (){
		for (int i = 0; i < MAXVAL; i ++){
			for ( int j = 0; j < MAXVAL; j ++ ) {
			}
		}
	}
	private static void emptyFInt (){
		FixedInt k = new FixedInt(16);
		FixedInt fMaxVal = k.createInt(MAXVAL);
		FixedInt fInc = k.createInt(1);
		for (FixedInt i = k.createInt(0); i.getValue() < fMaxVal.getValue(); i = i.add(fInc)){
			for (FixedInt j = k.createInt(0); j.getValue() < fMaxVal.getValue(); j = j.add(fInc)){
			}
		}
	}


	private static void multiplyInt (){
		int k = 0;
		for (int i = 0; i < MAXVAL; i ++){
			for ( int j = 0; j < MAXVAL; j ++ ) {
				k += k * i * j;
			}
		}
	}
	private static void multiplyFInt (){
		FixedInt k = new FixedInt(16).createInt(0);
		
		FixedInt fMaxVal = k.createInt(MAXVAL);
		FixedInt fInc = k.createInt(1);
		for (FixedInt i = k.createInt(0); i.getValue() < fMaxVal.getValue(); i = i.add(fInc)){
			for (FixedInt j = k.createInt(0); j.getValue() < fMaxVal.getValue(); j = j.add(fInc)){
				k = k.add (k.mul( i.mul (j) ));
			}
		}
		
	}

Most likely, however there is still an overhead (as with my example). The example above of k = k.add(k.mul( i.mul (j))); could easily be optimized to creating only one new instance! But this is just the extreme case of using a truly immutable type. The FixedInt i and j were necessary since you would have to convert them anyway so you might as well just have them as FixedInt’s

Just remember one of the reasons the VM guarantees the memory is zeroed is to give you a known state for a new object - one of the classic reasons C programs go awry unexpectedly is having cruddy data in a struct. With pooling you lose that safety net and you’re on your own again.

Cas :slight_smile:

But C guarantees the memory will be uncertain, and whatever you don’t initialize may not be 0 :smiley: And 0 isn’t a safety net if you don’t wnat 0 either :slight_smile:

Hehe :slight_smile: There is a subtle but big difference in having guaranteed default values, and that’s repeatable crashes :slight_smile:

Cas :slight_smile:

lol yes, funny but true. Like when beginners test their games in VBA and find that it doesn’t work in No$ and real hardware - although that’s almost the opposite.

Well the whole reason for me creating the FixedInt class was so that I could have integer precision and predictability without having to worry about the correctness of the arithmetic statements (i.e. shifting and performing operations with different point integers). Having said that I will probably change it to floating point anyway, but it did create a fine example of creating something that works over something that is fast (if you get what I mean)!

By the way -1>>1 = -1 :frowning:

duplicates the most-significant-bit

inserts zeroes.

-1 >>> 1 = 2 billion

Yes, well the way to get around that (providing you want to divide) is to write “-(-b>>1)” when b is negative.

i just read through this whole thread again, but i still do not fully understand.

so will object-pooling increase performance when i need thousands of new Vector3fs in each gameloop?

basically because it is costless to get an existing object, and it is cpu expansive to allocate (release when GC) memory for new object (even for one byte), when creating a new Object you ask the target OS RAM manager or java memory manager to give you an heap space, this is slow in comparaison of getting an existing memory allocated place, so using a pool for object this is what you do by getting a “vector” to an already allocated memory area. this is why it it will be always faster in any language to use pooled objects.

thanks for the info.
so short answer is yes, in this situation pooling will be better?

As always with performance, it depends on your implementation.

Just implement it, then tweak it, then compare it to creating new objects, then pick the fastest.