I've attached a lightly-tested sample alternative ObjectSpace implementation that you might use for inspiration. It is pure-Java (no JRuby stuff) so you'll have to adapt it.
The key points are: - A list of arrays of references is used instead of just a list of references. This gives you more control by letting you do a cleanup only when you are about to allocate another array. It also avoids the internal array copying that happens when an ArrayList is resized. - It uses a BitSet to keep track of which indexes are used. During cleanup it iterates over all of the used indexes and checks to see if each WeakReference value has been collected. I wasn't sure if the order of the objects returned by iterator matters, if so you'd have to compact the arrays in cleanup instead of just nulling out unused slots. This would make it easier to discard entirely empty arrays, but it would probably be a net loss performance-wise (and more complex). There are some alternative cleanup implementations, for example creating a "WeakRefWithIndex" class that extends WeakReference and keeps track of the array index. Cleanup then would poll a ReferenceQueue and zero out the indexes of the dead references. I tried this and unsurprisingly it uses less total memory (because indexes are freed ASAP) but is slower overall. I've compared the performance to the existing JRuby code and this is about two times faster on my machine. I hope there is more that can be done but honestly reducing the number of objects that get registered with ObjectSpace is probably the best bet (e.g. perhaps you could detect if any client code will ever call iterator). You could also defer creation of the ObjectSpace until it is requested for the first time and then build it by leveraging the JVM profiler support (walk all live objects looking for JRuby ones). I'm not volunteering :-) Chris ==================================================================== import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.*; public class ObjectSpace { private static final int CHUNK_SIZE = 0x2000; private List chunks = new ArrayList(); private BitSet bits = new BitSet(); private int clearIndex; private int max; synchronized public void add(Object obj) { int index = bits.nextClearBit(clearIndex); if (index >= max) { cleanup(); index = bits.nextClearBit(0); if (index >= max) { // all slots are filled, allocate new chunk chunks.add(new WeakReference[CHUNK_SIZE]); max = chunks.size() * CHUNK_SIZE; } } ((WeakReference[])chunks.get(index / CHUNK_SIZE))[index % CHUNK_SIZE] = new WeakReference(obj); bits.set(index); clearIndex = index + 1; } private void cleanup() { for (int i = bits.nextSetBit(0); i >= 0; i = bits.nextSetBit(i + 1)) { WeakReference[] chunk = (WeakReference[])chunks.get(i / CHUNK_SIZE); if (chunk[i % CHUNK_SIZE].get() == null) { chunk[i % CHUNK_SIZE] = null; bits.clear(i); } } } public Iterator iterator() { return new ObjectSpaceIterator(); } private class ObjectSpaceIterator implements Iterator { private int setIndex; private Object next; public ObjectSpaceIterator() { advance(); } public boolean hasNext() { return next != null; } public Object next() { Object result = next; advance(); return next; } public void remove() { throw new UnsupportedOperationException(); } private void advance() { next = null; synchronized (ObjectSpace.this) { while (next == null) { int index = bits.nextSetBit(setIndex); if (index == -1) return; setIndex = index + 1; WeakReference ref = ((WeakReference[])chunks.get(index / CHUNK_SIZE))[index % CHUNK_SIZE]; if (ref != null) next = ref.get(); } } } } } _______________________________________________ Jruby-devel mailing list Jruby-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jruby-devel