SafetyMutex and rocket optimization updates
[debian/openrocket] / src / net / sf / openrocket / util / MemoryManagement.java
1 package net.sf.openrocket.util;
2
3 import java.lang.ref.WeakReference;
4 import java.util.ArrayList;
5 import java.util.Iterator;
6 import java.util.LinkedList;
7 import java.util.List;
8
9 import net.sf.openrocket.logging.LogHelper;
10 import net.sf.openrocket.startup.Application;
11
12 /**
13  * A class that performs certain memory-management operations for debugging purposes.
14  * For example, complex objects that are being discarded and that should be garbage-collectable
15  * (such as dialog windows) should be registered for monitoring by calling
16  * {@link #collectable(Object)}.  This will allow monitoring whether the object really is
17  * garbage-collected or whether it is retained in memory due to a memory leak.
18  * Only complex objects should be registered due to the overhead of the monitoring.
19  * 
20  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
21  */
22 public final class MemoryManagement {
23         private static final LogHelper log = Application.getLogger();
24         
25         /** Purge cleared references every this many calls to {@link #collectable(Object)} */
26         private static final int PURGE_CALL_COUNT = 100;
27         
28
29         /**
30          * Storage of the objects.  This is basically a mapping from the objects (using weak references)
31          * to 
32          */
33         private static List<MemoryData> objects = new LinkedList<MemoryData>();
34         private static int callCount = 0;
35         
36         
37         private MemoryManagement() {
38         }
39         
40         
41         /**
42          * Mark an object that should be garbage-collectable by the GC.  This class will monitor
43          * whether the object actually gets garbage-collected or not by holding a weak reference
44          * to the object.
45          * 
46          * @param o             the object to monitor.
47          */
48         public static synchronized void collectable(Object o) {
49                 if (o == null) {
50                         throw new IllegalArgumentException("object is null");
51                 }
52                 log.debug("Adding object into collectable list: " + o);
53                 objects.add(new MemoryData(o));
54                 callCount++;
55                 if (callCount % PURGE_CALL_COUNT == 0) {
56                         purge();
57                 }
58         }
59         
60         
61         /**
62          * Return the number of times {@link #collectable(Object)} has been called.
63          * @return      the number of times {@link #collectable(Object)} has been called.
64          */
65         public static synchronized int getCallCount() {
66                 return callCount;
67         }
68         
69         
70         /**
71          * Return a list of MemoryData objects corresponding to the objects that have been
72          * registered by {@link #collectable(Object)} and have not been garbage-collected properly.
73          * This method first calls <code>System.gc()</code> multiple times to attempt to
74          * force any remaining garbage collection.
75          * 
76          * @return      a list of MemoryData objects for objects that have not yet been garbage-collected.
77          */
78         public static synchronized ArrayList<MemoryData> getRemainingObjects() {
79                 for (int i = 0; i < 5; i++) {
80                         System.runFinalization();
81                         System.gc();
82                         try {
83                                 Thread.sleep(1);
84                         } catch (InterruptedException e) {
85                         }
86                 }
87                 purge();
88                 return new ArrayList<MemoryData>(objects);
89         }
90         
91         
92
93         /**
94          * Purge all cleared references from the object list.
95          */
96         private static void purge() {
97                 int origCount = objects.size();
98                 Iterator<MemoryData> iterator = objects.iterator();
99                 while (iterator.hasNext()) {
100                         MemoryData data = iterator.next();
101                         if (data.getReference().get() == null) {
102                                 iterator.remove();
103                         }
104                 }
105                 log.debug(objects.size() + " of " + origCount + " objects remaining in discarded objects list after purge.");
106         }
107         
108         
109         /**
110          * A value object class containing data of a discarded object reference.
111          */
112         public static final class MemoryData {
113                 private final WeakReference<Object> reference;
114                 private final long registrationTime;
115                 
116                 private MemoryData(Object object) {
117                         this.reference = new WeakReference<Object>(object);
118                         this.registrationTime = System.currentTimeMillis();
119                 }
120                 
121                 /**
122                  * Return the weak reference to the discarded object.
123                  */
124                 public WeakReference<Object> getReference() {
125                         return reference;
126                 }
127                 
128                 /**
129                  * Return the time when the object was discarded.
130                  * @return      a millisecond timestamp of when the object was discarded.
131                  */
132                 public long getRegistrationTime() {
133                         return registrationTime;
134                 }
135         }
136         
137 }