source: josm/trunk/src/org/openstreetmap/josm/tools/MemoryManager.java@ 13202

Last change on this file since 13202 was 12624, checked in by Don-vip, 7 years ago

see #15182 - remove unused imports

File size: 6.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.text.MessageFormat;
6import java.util.ArrayList;
7import java.util.List;
8import java.util.function.Supplier;
9
10/**
11 * This class allows all components of JOSM to register reclaimable amounts to memory.
12 * <p>
13 * It can be used to hold imagery caches or other data that can be reconstructed form disk/web if required.
14 * <p>
15 * Reclaimable storage implementations may be added in the future.
16 *
17 * @author Michael Zangl
18 * @since 10588
19 */
20public class MemoryManager {
21 /**
22 * assumed minimum JOSM memory footprint
23 */
24 private static final long JOSM_CORE_FOOTPRINT = 50L * 1024L * 1024L;
25
26 private static final MemoryManager INSTANCE = new MemoryManager();
27
28 private final ArrayList<MemoryHandle<?>> activeHandles = new ArrayList<>();
29
30 protected MemoryManager() {
31 }
32
33 /**
34 * Allocates a basic, fixed memory size.
35 * <p>
36 * If there is enough free memory, the factory is used to procude one element which is then returned as memory handle.
37 * <p>
38 * You should invoke {@link MemoryHandle#free()} if you do not need that handle any more.
39 * @param <T> The content type of the memory-
40 * @param name A name for the memory area. Only used for debugging.
41 * @param maxBytes The maximum amount of bytes the content may have
42 * @param factory The factory to use to procude the content if there is sufficient memory.
43 * @return A memory handle to the content.
44 * @throws NotEnoughMemoryException If there is not enough memory to allocate.
45 */
46 public synchronized <T> MemoryHandle<T> allocateMemory(String name, long maxBytes, Supplier<T> factory) throws NotEnoughMemoryException {
47 if (isAvailable(maxBytes)) {
48 T content = factory.get();
49 if (content == null) {
50 throw new IllegalArgumentException("Factory did not return a content element.");
51 }
52 Logging.info(MessageFormat.format("Allocate for {0}: {1} MB of memory. Available: {2} MB.",
53 name, maxBytes / 1024 / 1024, getAvailableMemory() / 1024 / 1024));
54 MemoryHandle<T> handle = new ManualFreeMemoryHandle<>(name, content, maxBytes);
55 activeHandles.add(handle);
56 return handle;
57 } else {
58 throw new NotEnoughMemoryException(maxBytes);
59 }
60 }
61
62 /**
63 * Check if that memory is available
64 * @param maxBytes The memory to check for
65 * @return <code>true</code> if that memory is available.
66 */
67 public synchronized boolean isAvailable(long maxBytes) {
68 if (maxBytes < 0) {
69 throw new IllegalArgumentException(MessageFormat.format("Cannot allocate negative number of bytes: {0}", maxBytes));
70 }
71 return getAvailableMemory() >= maxBytes;
72 }
73
74 /**
75 * Gets the maximum amount of memory available for use in this manager.
76 * @return The maximum amount of memory.
77 */
78 public synchronized long getMaxMemory() {
79 return Runtime.getRuntime().maxMemory() - JOSM_CORE_FOOTPRINT;
80 }
81
82 /**
83 * Gets the memory that is considered free.
84 * @return The memory that can be used for new allocations.
85 */
86 public synchronized long getAvailableMemory() {
87 return getMaxMemory() - activeHandles.stream().mapToLong(MemoryHandle::getSize).sum();
88 }
89
90 /**
91 * Get the global memory manager instance.
92 * @return The memory manager.
93 */
94 public static MemoryManager getInstance() {
95 return INSTANCE;
96 }
97
98 /**
99 * Reset the state of this manager to the default state.
100 * @return true if there were entries that have been reset.
101 */
102 protected synchronized List<MemoryHandle<?>> resetState() {
103 ArrayList<MemoryHandle<?>> toFree = new ArrayList<>(activeHandles);
104 toFree.forEach(MemoryHandle::free);
105 return toFree;
106 }
107
108 /**
109 * A memory area managed by the {@link MemoryManager}.
110 * @author Michael Zangl
111 * @param <T> The content type.
112 */
113 public interface MemoryHandle<T> {
114
115 /**
116 * Gets the content of this memory area.
117 * <p>
118 * This method should be the prefered access to the memory since it will do error checking when {@link #free()} was called.
119 * @return The memory area content.
120 */
121 T get();
122
123 /**
124 * Get the size that was requested for this memory area.
125 * @return the size
126 */
127 long getSize();
128
129 /**
130 * Manually release this memory area. There should be no memory consumed by this afterwards.
131 */
132 void free();
133 }
134
135 private class ManualFreeMemoryHandle<T> implements MemoryHandle<T> {
136 private final String name;
137 private T content;
138 private final long size;
139
140 ManualFreeMemoryHandle(String name, T content, long size) {
141 this.name = name;
142 this.content = content;
143 this.size = size;
144 }
145
146 @Override
147 public T get() {
148 if (content == null) {
149 throw new IllegalStateException(MessageFormat.format("Memory area was accessed after free(): {0}", name));
150 }
151 return content;
152 }
153
154 @Override
155 public long getSize() {
156 return size;
157 }
158
159 @Override
160 public void free() {
161 if (content == null) {
162 throw new IllegalStateException(MessageFormat.format("Memory area was already marked as freed: {0}", name));
163 }
164 content = null;
165 synchronized (MemoryManager.this) {
166 activeHandles.remove(this);
167 }
168 }
169
170 @Override
171 public String toString() {
172 return "MemoryHandle [name=" + name + ", size=" + size + ']';
173 }
174 }
175
176 /**
177 * This exception is thrown if there is not enough memory for allocating the given object.
178 * @author Michael Zangl
179 */
180 public static class NotEnoughMemoryException extends Exception {
181 NotEnoughMemoryException(long memoryBytesRequired) {
182 super(tr("To add another layer you need to allocate at least {0,number,#}MB memory to JOSM using -Xmx{0,number,#}M "
183 + "option (see http://forum.openstreetmap.org/viewtopic.php?id=25677).\n"
184 + "Currently you have {1,number,#}MB memory allocated for JOSM",
185 memoryBytesRequired / 1024 / 1024, Runtime.getRuntime().maxMemory() / 1024 / 1024));
186 }
187 }
188}
Note: See TracBrowser for help on using the repository browser.