1 /*
2  * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.management;
27 
28 import java.lang.management.ManagementFactory;
29 import java.lang.management.MemoryPoolMXBean;
30 import java.lang.management.MemoryUsage;
31 import java.lang.management.MemoryType;
32 import java.lang.management.MemoryManagerMXBean;
33 import javax.management.openmbean.CompositeData;
34 import javax.management.ObjectName;
35 
36 import static java.lang.management.MemoryNotificationInfo.*;
37 
38 /**
39  * Implementation class for a memory pool.
40  * Standard and committed hotspot-specific metrics if any.
41  *
42  * ManagementFactory.getMemoryPoolMXBeans() returns a list of
43  * instances of this class.
44  */
45 class MemoryPoolImpl implements MemoryPoolMXBean {
46 
47     private final String  name;
48     private final boolean isHeap;
49     private final boolean isValid;
50     private final boolean collectionThresholdSupported;
51     private final boolean usageThresholdSupported;
52 
53     private MemoryManagerMXBean[] managers;
54 
55     private long  usageThreshold;
56     private long  collectionThreshold;
57 
58     private boolean usageSensorRegistered; // VM-initialized to false
59     private boolean gcSensorRegistered;    // VM-initialized to false
60     private final Sensor usageSensor;
61     private final Sensor gcSensor;
62 
MemoryPoolImpl(String name, boolean isHeap, long usageThreshold, long gcThreshold)63     MemoryPoolImpl(String name, boolean isHeap, long usageThreshold,
64                    long gcThreshold) {
65         this.name = name;
66         this.isHeap = isHeap;
67         this.isValid = true;
68         this.managers = null;
69         this.usageThreshold = usageThreshold;
70         this.collectionThreshold = gcThreshold;
71         this.usageThresholdSupported = (usageThreshold >= 0);
72         this.collectionThresholdSupported = (gcThreshold >= 0);
73         this.usageSensor = new PoolSensor(this, name + " usage sensor");
74         this.gcSensor = new CollectionSensor(this, name + " collection sensor");
75     }
76 
getName()77     public String getName() {
78         return name;
79     }
80 
isValid()81     public boolean isValid() {
82         return isValid;
83     }
84 
getType()85     public MemoryType getType() {
86         if (isHeap) {
87             return MemoryType.HEAP;
88         } else {
89             return MemoryType.NON_HEAP;
90         }
91     }
92 
getUsage()93     public MemoryUsage getUsage() {
94         return getUsage0();
95     }
96 
getPeakUsage()97     public synchronized MemoryUsage getPeakUsage() {
98         // synchronized since resetPeakUsage may be resetting the peak usage
99         return getPeakUsage0();
100     }
101 
getUsageThreshold()102     public synchronized long getUsageThreshold() {
103         if (!isUsageThresholdSupported()) {
104             throw new UnsupportedOperationException(
105                 "Usage threshold is not supported");
106         }
107         return usageThreshold;
108     }
109 
setUsageThreshold(long newThreshold)110     public void setUsageThreshold(long newThreshold) {
111         if (!isUsageThresholdSupported()) {
112             throw new UnsupportedOperationException(
113                 "Usage threshold is not supported");
114         }
115 
116         Util.checkControlAccess();
117 
118         MemoryUsage usage = getUsage0();
119         if (newThreshold < 0) {
120             throw new IllegalArgumentException(
121                 "Invalid threshold: " + newThreshold);
122         }
123 
124         if (usage.getMax() != -1 && newThreshold > usage.getMax()) {
125             throw new IllegalArgumentException(
126                 "Invalid threshold: " + newThreshold +
127                 " must be <= maxSize." +
128                 " Committed = " + usage.getCommitted() +
129                 " Max = " + usage.getMax());
130         }
131 
132         synchronized (this) {
133             if (!usageSensorRegistered) {
134                 // pass the sensor to VM to begin monitoring
135                 usageSensorRegistered = true;
136                 setPoolUsageSensor(usageSensor);
137             }
138             setUsageThreshold0(usageThreshold, newThreshold);
139             this.usageThreshold = newThreshold;
140         }
141     }
142 
getMemoryManagers()143     private synchronized MemoryManagerMXBean[] getMemoryManagers() {
144         if (managers == null) {
145             managers = getMemoryManagers0();
146         }
147         return managers;
148     }
149 
getMemoryManagerNames()150     public String[] getMemoryManagerNames() {
151         MemoryManagerMXBean[] mgrs = getMemoryManagers();
152 
153         String[] names = new String[mgrs.length];
154         for (int i = 0; i < mgrs.length; i++) {
155             names[i] = mgrs[i].getName();
156         }
157         return names;
158     }
159 
resetPeakUsage()160     public void resetPeakUsage() {
161         Util.checkControlAccess();
162 
163         synchronized (this) {
164             // synchronized since getPeakUsage may be called concurrently
165             resetPeakUsage0();
166         }
167     }
168 
isUsageThresholdExceeded()169     public boolean isUsageThresholdExceeded() {
170         if (!isUsageThresholdSupported()) {
171             throw new UnsupportedOperationException(
172                 "Usage threshold is not supported");
173         }
174 
175         // return false if usage threshold crossing checking is disabled
176         if (usageThreshold == 0) {
177             return false;
178         }
179 
180         MemoryUsage u = getUsage0();
181         return (u.getUsed() >= usageThreshold ||
182                 usageSensor.isOn());
183     }
184 
getUsageThresholdCount()185     public long getUsageThresholdCount() {
186         if (!isUsageThresholdSupported()) {
187             throw new UnsupportedOperationException(
188                 "Usage threshold is not supported");
189         }
190 
191         return usageSensor.getCount();
192     }
193 
isUsageThresholdSupported()194     public boolean isUsageThresholdSupported() {
195         return usageThresholdSupported;
196     }
197 
getCollectionUsageThreshold()198     public synchronized long getCollectionUsageThreshold() {
199         if (!isCollectionUsageThresholdSupported()) {
200             throw new UnsupportedOperationException(
201                 "CollectionUsage threshold is not supported");
202         }
203 
204         return collectionThreshold;
205     }
206 
setCollectionUsageThreshold(long newThreshold)207     public void setCollectionUsageThreshold(long newThreshold) {
208         if (!isCollectionUsageThresholdSupported()) {
209             throw new UnsupportedOperationException(
210                 "CollectionUsage threshold is not supported");
211         }
212 
213         Util.checkControlAccess();
214 
215         MemoryUsage usage = getUsage0();
216         if (newThreshold < 0) {
217             throw new IllegalArgumentException(
218                 "Invalid threshold: " + newThreshold);
219         }
220 
221         if (usage.getMax() != -1 && newThreshold > usage.getMax()) {
222             throw new IllegalArgumentException(
223                 "Invalid threshold: " + newThreshold +
224                      " > max (" + usage.getMax() + ").");
225         }
226 
227         synchronized (this) {
228             if (!gcSensorRegistered) {
229                 // pass the sensor to VM to begin monitoring
230                 gcSensorRegistered = true;
231                 setPoolCollectionSensor(gcSensor);
232             }
233             setCollectionThreshold0(collectionThreshold, newThreshold);
234             this.collectionThreshold = newThreshold;
235         }
236     }
237 
isCollectionUsageThresholdExceeded()238     public boolean isCollectionUsageThresholdExceeded() {
239         if (!isCollectionUsageThresholdSupported()) {
240             throw new UnsupportedOperationException(
241                 "CollectionUsage threshold is not supported");
242         }
243 
244         // return false if usage threshold crossing checking is disabled
245         if (collectionThreshold == 0) {
246             return false;
247         }
248 
249         MemoryUsage u = getCollectionUsage0();
250         return (gcSensor.isOn() ||
251                 (u != null && u.getUsed() >= collectionThreshold));
252     }
253 
getCollectionUsageThresholdCount()254     public long getCollectionUsageThresholdCount() {
255         if (!isCollectionUsageThresholdSupported()) {
256             throw new UnsupportedOperationException(
257                 "CollectionUsage threshold is not supported");
258         }
259 
260         return gcSensor.getCount();
261     }
262 
getCollectionUsage()263     public MemoryUsage getCollectionUsage() {
264         return getCollectionUsage0();
265     }
266 
isCollectionUsageThresholdSupported()267     public boolean isCollectionUsageThresholdSupported() {
268         return collectionThresholdSupported;
269     }
270 
271     // Native VM support
getUsage0()272     private native MemoryUsage getUsage0();
getPeakUsage0()273     private native MemoryUsage getPeakUsage0();
getCollectionUsage0()274     private native MemoryUsage getCollectionUsage0();
setUsageThreshold0(long current, long newThreshold)275     private native void setUsageThreshold0(long current, long newThreshold);
setCollectionThreshold0(long current, long newThreshold)276     private native void setCollectionThreshold0(long current, long newThreshold);
resetPeakUsage0()277     private native void resetPeakUsage0();
getMemoryManagers0()278     private native MemoryManagerMXBean[] getMemoryManagers0();
setPoolUsageSensor(Sensor s)279     private native void setPoolUsageSensor(Sensor s);
setPoolCollectionSensor(Sensor s)280     private native void setPoolCollectionSensor(Sensor s);
281 
282     // package private
283 
284     /**
285      * PoolSensor will be triggered by the VM when the memory
286      * usage of a memory pool is crossing the usage threshold.
287      * The VM will not trigger this sensor in subsequent crossing
288      * unless the memory usage has returned below the threshold.
289      */
290     class PoolSensor extends Sensor {
291         final MemoryPoolImpl pool;
292 
PoolSensor(MemoryPoolImpl pool, String name)293         PoolSensor(MemoryPoolImpl pool, String name) {
294             super(name);
295             this.pool = pool;
296         }
triggerAction(MemoryUsage usage)297         void triggerAction(MemoryUsage usage) {
298             // create and send notification
299             MemoryImpl.createNotification(MEMORY_THRESHOLD_EXCEEDED,
300                                           pool.getName(),
301                                           usage,
302                                           getCount());
303         }
triggerAction()304         void triggerAction() {
305             // do nothing
306         }
clearAction()307         void clearAction() {
308             // do nothing
309         }
310     }
311 
312     /**
313      * CollectionSensor will be triggered and cleared by the VM
314      * when the memory usage of a memory pool after GC is crossing
315      * the collection threshold.
316      * The VM will trigger this sensor in subsequent crossing
317      * regardless if the memory usage has changed since the previous GC.
318      */
319     class CollectionSensor extends Sensor {
320         final MemoryPoolImpl pool;
CollectionSensor(MemoryPoolImpl pool, String name)321         CollectionSensor(MemoryPoolImpl pool, String name) {
322             super(name);
323             this.pool = pool;
324         }
triggerAction(MemoryUsage usage)325         void triggerAction(MemoryUsage usage) {
326             MemoryImpl.createNotification(MEMORY_COLLECTION_THRESHOLD_EXCEEDED,
327                                           pool.getName(),
328                                           usage,
329                                           gcSensor.getCount());
330         }
triggerAction()331         void triggerAction() {
332             // do nothing
333         }
clearAction()334         void clearAction() {
335             // do nothing
336         }
337     }
338 
getObjectName()339     public ObjectName getObjectName() {
340         return Util.newObjectName(ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE, getName());
341     }
342 
343 }
344