最近在写编辑器(Java+JOGL)的碰撞检测模块,检测函数中,需要用到大量的临时对象,Vector3f, Matrix4f,诸如此类; Java本来就慢,如果我们毫无顾忌的使用 new, 真的是不好意思。。。幸好发现了这个ObjectPool的概念,虽然很简单,但很实用。
/**
*
* @author Yong.Xue
*/
public class IPoolVec3 {
private static ArrayList objects = new ArrayList(256);
private static int n = 256;
public static Vector3f Alloc(float x, float y, float z) {
if(n > 0) {
Vector3f v = objects.remove(--n);
v.set(x, y, z);
return v;
} else {
return new Vector3f();
}
}
public static Vector3f Alloc() {
if(n > 0) {
Vector3f v = objects.remove(--n);
v.zero();
return v;
} else {
return new Vector3f();
}
}
public static void Free(Vector3f v) {
if(v == null) {
return;
}
objects.add(v);
++n;
}
}
使用方法如下
/**
* Tests the triangle for intersection with a ray.
* @param ray
* @return the distance between the ray origin and the intersection point
*/
public float Intersect(IRay ray) {
// map tmp vectors to local names
Vector3f e1 = IPoolVec3.Alloc();
Vector3f e2 = IPoolVec3.Alloc();
Vector3f p = IPoolVec3.Alloc();
Vector3f q = IPoolVec3.Alloc();
Vector3f s = IPoolVec3.Alloc();
try {
// test raydirection
e1.sub(m_pvPositions[1], m_pvPositions[0]);
e2.sub(m_pvPositions[2], m_pvPositions[0]);
p.cross(ray.m_vDirection, e2);
float a = e1.dot(p);
// if the result is "zero", the pick ray is parallel to the triangle
if ((-IMath.EPSILON < a) && (a < IMath.EPSILON)) {
return (-1f);
}
float f = 1.0f / a;
// compute barycentric coordinates
s.sub(ray.m_vOrigin, m_pvPositions[0]);
final float u = f * s.dot(p);
if ((0.0f > u) || (u > 1.0f)) {
return (-1f);
}
q.cross(s, e1);
final float v = f * ray.m_vDirection.dot(q);
if ((0.0f > u) || (u + v > 1.0f)) {
return (-1f);
}
// compute the intersection point on the ray
final float l = f * e2.dot(q);
if (l < 0.0f) {
return (-1f);
}
return (l * l);
} finally {
IPoolVec3.Free(s);
IPoolVec3.Free(q);
IPoolVec3.Free(p);
IPoolVec3.Free(e2);
IPoolVec3.Free(e1);
}
}
恩,所有的临时对象都不是new,而是从object pool中取得一个引用;如果pool里没有了,才实行new操作;
最重要的一点是,使用完毕后,一定要归还啊,否则就会造成类似C/C++中的内存泄漏,pool中可用元素越来越少。。