When you are using writeUnshared
on the writing side you have already done one half of the job. If you now also use readUnshared
on the input side rather than readObject
, the ObjectInputStream
will not maintain references to the objects.
You can use the following program to verify the behavior:
package lib.io;
import java.awt.Button;
import java.io.*;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.concurrent.ConcurrentHashMap;
public class ObjectInputStreamReferences {
public static void main(String[] args)
throws IOException, ClassNotFoundException {
final int numObjects=1000;
Serializable s=new Button();
ByteArrayOutputStream os=new ByteArrayOutputStream();
try( ObjectOutputStream oos=new ObjectOutputStream(os) ) {
for(int i=0; i<numObjects; i++) oos.writeUnshared(s);
}
final ConcurrentHashMap<WeakReference<?>, Object> map
=new ConcurrentHashMap<>();
final ReferenceQueue<Object> q=new ReferenceQueue<>();
new Thread(new Runnable() {
public void run() {
reportCollections(map, q);
}
}).start();
try(ObjectInputStream ois=
new ObjectInputStream(new ByteArrayInputStream(os.toByteArray()))) {
for(int i=0; i<numObjects; i++) {
Object o=ois.readUnshared();
map.put(new WeakReference<>(o,q), "");
o=null;
System.gc();Thread.yield();
}
}
System.exit(0);
}
static void reportCollections(
ConcurrentHashMap<WeakReference<?>, Object> map, ReferenceQueue<?> q) {
for(;;) try {
Reference<?> removed = q.remove();
System.out.println("one object collected");
map.remove(removed);
} catch(InterruptedException ex){}
}
}