Pool Management Object Reuse

- 79 - Note that different VM environments produce different figures. If you plot object size against object-creation time for various environments, most plots are monotonically increasing, i.e., it takes more time to create larger objects. But there are discrepancies here too. For example, Netscape Version 4 running on Windows has the peculiar behavior that objects of size 4 and 12 int s are created fastest refer to http:www.javaworld.comjavaworldjw-09-1998jw-09-speed.html . Also, note that JIT VMs actually have a worse problem with object creation relative to other VM activities, because JIT VMs can speed up almost every other activity, but object creation is nearly as slow as if the JIT compiler was not there.

4.2 Object Reuse

As we saw in the last section, objects are expensive to create. Where it is reasonable to reuse the same object, you should do so. You need to be aware of when not to call new . One fairly obvious situation is when you have already used an object and can discard it before you are about to create another object of the same class. You should look at the object and consider whether it is possible to reset the fields and then reuse the object, rather than throw it away and create another. This can be particularly important for objects that are constantly used and discarded: for example, in graphics processing, objects such as Rectangle s, Point s, Color s, and Font s are used and discarded all the time. Recycling these types of objects can certainly improve performance. Recycling can also apply to the internal elements of structures. For example, a linked list has nodes added to it as it grows, and as it shrinks, the nodes are discarded. Holding on to the discarded nodes is an obvious way to recycle these objects and reduce the cost of object creation.

4.2.1 Pool Management

Most container objects e.g., Vector s, Hashtable s can be reused rather than created and thrown away. Of course, while you are not using the retained objects, you are holding on to more memory than if you simply discarded those objects, and this reduces the memory available to create other objects. You need to balance the need to have some free memory available against the need to improve performance by reusing objects. But generally, the space taken by retaining objects for later reuse is significant only for very large collections, and you should certainly know which ones these are in your application. Note that when recycling container objects, you need to dereference all the elements previously in the container so that you dont prevent them from being garbage collected . Because there is this extra overhead in recycling, it may not always be worth recycling containers. As usual for tuning, this technique is best applied to ameliorate an object-creation bottleneck that has already been identified. A good strategy for reusing container objects is to use your own container classes, possibly wrapping other containers. This gives you a high degree of control over each collection object, and you can design these specifically for reuse. You can still use a pool manager to manage your requirements, even without reuse-designed classes. Reusing classes requires extra work when youve finished with a collection object, but the effort is worth it when reuse is possible. The code fragment here shows how you could use a vector pool manager: An instance of the vector pool manager. public static VectorPoolManager vectorPoolManager = new VectorPoolManager25; ... - 80 - public void someMethod { Get a new Vector. We only use the vector to do some stuff within this method, and then we dump the vector i.e. it is not returned or assigned to a state variable so this is a perfect candidate for reusing Vectors. Use a factory method instead of new Vector Vector v = vectorPoolManager.getVector ; ... do vector manipulation stuff and the extra work is that we have to explicitly tell the pool manager that we have finished with the vector vectorPoolManager.returnVectorv; } Note that nothing stops the application from retaining a handle on a vector after it has been returned to the pool, and obviously that could lead to a classic inadvertent reuse of memory bug . You need to ensure that handles to vectors are not held anywhere: these Vector s should be used only internally within an application, not externally in third-party classes where a handle may be retained. The following class manages a pool of Vector s: package tuning.reuse; import java.util.Vector; public class VectorPoolManager { Vector[] pool; boolean[] inUse; public VectorPoolManagerint initialPoolSize { pool = new Vector[initialPoolSize]; inUse = new boolean[initialPoolSize]; for int i = pool.length-1; i=0; i-- { pool[i] = new Vector ; inUse[i] = false; } } public synchronized Vector getVector { for int i = inUse.length-1; i = 0; i-- if inUse[i] { inUse[i] = true; return pool[i]; } If we got here, then all the Vectors are in use. We will increase the number in our pool by 10 arbitrary value for illustration purposes. boolean[] old_inUse = inUse; inUse = new boolean[old_inUse.length+10]; System.arraycopyold_inUse, 0, inUse, 0, old_inUse.length; Vector[] old_pool = pool; pool = new Vector[old_pool.length+10]; System.arraycopyold_pool, 0, pool, 0, old_pool.length; - 81 - for int i = old_pool.length; i pool.length; i++ { pool[i] = new Vector ; inUse[i] = false; } and allocate the last Vector inUse[pool.length-1] = true; return pool[pool.length-1]; } public synchronized void returnVectorVector v { for int i = inUse.length-1; i = 0; i-- if pool[i] == v { inUse[i] = false; Can use clear for java.util.Collection objects Note that setSize nulls out all elements v.setSize0; return; } throw new RuntimeExceptionVector was not obtained from the pool: + v; } } Because you reset the Vector size to when it is returned to the pool, all objects previously referenced from the vector are no longer referenced the Vector.setSize method null s out all internal index entries beyond the new size to ensure no reference is retained. However, at the same time, you do not return any memory allocated to the Vector itself, because the Vector s current capacity is retained. A lazily initialized version of this class simply starts with zero items in the pool and sets the pool to grow by one or more each time. Many JDK collection classes, including java.util.Vector , have both a size and a capacity. The capacity is the number of elements the collection can hold before that collection needs to resize its internal memory to be larger. The size is the number of externally accessible elements the collection is actually holding. The capacity is always greater than or equal to the size. By holding spare capacity, elements can be added to collections without having to continually resize the underlying memory. This makes element addition faster and more efficient.

4.2.2 ThreadLocals