1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
package vtk;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.TreeSet;
import java.util.concurrent.locks.ReentrantLock;
/**
* Provide a Java thread safe implementation of vtkJavaMemoryManager. This does
* not make VTK thread safe. This only insure that the change of reference count
* will never happen in two concurrent thread in the Java world.
*
* @see vtkJavaMemoryManager
* @author sebastien jourdain - sebastien.jourdain@kitware.com
*/
public class vtkJavaMemoryManagerImpl implements vtkJavaMemoryManager {
private vtkJavaGarbageCollector garbageCollector;
private ReentrantLock lock;
private vtkReferenceInformation lastGcResult;
private HashMap<Long, WeakReference<vtkObjectBase>> objectMap;
private HashMap<Long, String> objectMapClassName;
public vtkJavaMemoryManagerImpl() {
this.lock = new ReentrantLock();
this.objectMap = new HashMap<Long, WeakReference<vtkObjectBase>>();
this.objectMapClassName = new HashMap<Long, String>();
this.garbageCollector = new vtkJavaGarbageCollector();
}
// Thread safe
public vtkObjectBase getJavaObject(Long vtkId) {
// Check pre-condition
if (vtkId == null || vtkId.longValue() == 0) {
throw new RuntimeException("Invalid ID, can not be null or equal to 0.");
}
// Check inside the map if the object is already there
WeakReference<vtkObjectBase> value = objectMap.get(vtkId);
vtkObjectBase resultObject = (value == null) ? null : value.get();
// If not, we have to do something
if (value == null || resultObject == null) {
try {
// Make sure no concurrency could happen inside that
this.lock.lock();
// Now that we have the lock make sure someone else didn't
// create the object in between, if so just return the created
// instance
value = objectMap.get(vtkId);
resultObject = (value == null) ? null : value.get();
if (resultObject != null) {
return resultObject;
}
// We need to do the work of the gc
if (value != null && resultObject == null) {
this.unRegisterJavaObject(vtkId);
}
// No-one did create it, so let's do it
if (resultObject == null) {
try {
String className = vtkObjectBase.VTKGetClassNameFromReference(vtkId.longValue());
Class<?> c = Class.forName("vtk." + className);
Constructor<?> cons = c.getConstructor(new Class<?>[] { long.class });
resultObject = (vtkObjectBase) cons.newInstance(new Object[] { vtkId });
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
this.lock.unlock();
}
}
return resultObject;
}
// Thread safe
public void registerJavaObject(Long id, vtkObjectBase obj) {
try {
this.lock.lock();
this.objectMap.put(id, new WeakReference<vtkObjectBase>(obj));
this.objectMapClassName.put(id, obj.GetClassName());
} finally {
this.lock.unlock();
}
}
// Thread safe
public void unRegisterJavaObject(Long id) {
try {
this.lock.lock();
this.objectMapClassName.remove(id);
WeakReference<vtkObjectBase> value = this.objectMap.remove(id);
// Prevent double deletion...
if (value != null) {
vtkObjectBase.VTKDeleteReference(id.longValue());
} else {
throw new RuntimeException("You try to delete a vtkObject that is not referenced in the Java object Map. You may have call Delete() twice.");
}
} finally {
this.lock.unlock();
}
}
// Thread safe
public vtkReferenceInformation gc(boolean debug) {
System.gc();
try {
this.lock.lock();
final vtkReferenceInformation infos = new vtkReferenceInformation(debug);
for (Long id : new TreeSet<Long>(this.objectMap.keySet())) {
vtkObjectBase obj = this.objectMap.get(id).get();
if (obj == null) {
infos.addFreeObject(this.objectMapClassName.get(id));
this.unRegisterJavaObject(id);
} else {
infos.addKeptObject(this.objectMapClassName.get(id));
}
}
this.lastGcResult = infos;
return infos;
} finally {
this.lock.unlock();
}
}
public vtkJavaGarbageCollector getAutoGarbageCollector() {
return this.garbageCollector;
}
// Thread safe
public int deleteAll() {
int size = this.objectMap.size();
try {
this.lock.lock();
for (Long id : new TreeSet<Long>(this.objectMap.keySet())) {
this.unRegisterJavaObject(id);
}
} finally {
this.lock.unlock();
}
return size;
}
public int getSize() {
return objectMap.size();
}
public vtkReferenceInformation getLastReferenceInformation() {
return this.lastGcResult;
}
}
|