Reuse objects

"Martin Carlberg" <[email protected]> Wed, 24 Sep 2003 10:28:10 +0200
Newsgroups gmane.comp.web.webobjects.eof,gmane.comp.web.webobjects.devel
Message-ID <[email protected]>
Hello!

I have written some code to reuse attribute objects in 
enterprise objects. I have an application that caches a 
lot of information from the database in memory (around 
500MB). When I analysed it, I could see many attributes 
that contained the same thing. I wanted to do something 
about it.

In many sessions at WWDC over the years I have been told 
not to reuse objects with pools or other implementations. 
Just make new objects and the Java VM will take care of 
it. Now I did a pool anyway just for testing and I found 
out that I saved 12% of memory and the code was around 2% 
faster. Yes it was faster because I don't need to use the 
"equals" method. I could just compare if two objects are 
the same.

Now this is probably not for the average application but 
it works in this one. Has someone else experiences on 
this. Is this the way to go? Is it possible to improve my 
implementation? Is it safe to deploy? I would like to get 
any thoughts or feedback on this.

I have supplied some code. The ReuseObject class handles 
the pool of objects to reuse. The Application class adds 
itself as a delegate to grab the rows from the database. I 
also made sure that all the set methods in the EO classes 
are modified like the example at the bottom.

I'm using WebObjects 5.1 on Windows 2000.


Best regards,

- Martin Carlberg
- System Developer
- Oops AB
- http://oops.se

import java.lang.ref.*;
import java.util.*;

import com.webobjects.foundation.*;

public class ReuseObject {
  private static WeakHashMap reusableObjects = new 
WeakHashMap(3000);

  public static Object reuseObjectForObject(Object 
anObject) {
   WeakReference cachedObjectRef = 
(WeakReference)reusableObjects.get(anObject);
   if (cachedObjectRef != null) {
    Object cachedObject = cachedObjectRef.get();
    if (cachedObject != null) {
     return cachedObject;
    }
   }
   reusableObjects.put(anObject, new 
WeakReference(anObject));
   return anObject;
  }

  public static void 
reuseObjectsInDictionary(NSMutableDictionary dict) {
   Enumeration enum = dict.keyEnumerator();
   while (enum.hasMoreElements()) {
    Object key = enum.nextElement();
    Object value = dict.objectForKey(key);
    Object reuseObject = reuseObjectForObject(value);
    if (reuseObject != value) {
     dict.setObjectForKey(reuseObject, key);
    }
   }
  }
}


public class Application extends WOApplication  {
  public Application() {
   super();
   EOAdaptorContext.setDefaultDelegate(this);
  }

  public void adaptorChannelDidFetchRow(Object channel, 
NSMutableDictionary row) {
   ReuseObject.reuseObjectsInDictionary(row);
  }
}


public class DatabaseObject extends EOGenericRecord {
  public void setName(String value) {
   takeStoredValueForKey(ReuseObject.reuseObjectForObject(value), 
"name");
  }
}