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
26package sun.management;
27
28import java.lang.management.ManagementFactory;
29import java.lang.management.MemoryPoolMXBean;
30import java.lang.management.MemoryUsage;
31import java.lang.management.MemoryType;
32import java.lang.management.MemoryManagerMXBean;
33import javax.management.openmbean.CompositeData;
34import javax.management.ObjectName;
35
36import 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 */
45class 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;
59    private boolean gcSensorRegistered;
60    private Sensor  usageSensor;
61    private Sensor  gcSensor;
62
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        this.usageSensorRegistered = false;
76        this.gcSensorRegistered = false;
77    }
78
79    public String getName() {
80        return name;
81    }
82
83    public boolean isValid() {
84        return isValid;
85    }
86
87    public MemoryType getType() {
88        if (isHeap) {
89            return MemoryType.HEAP;
90        } else {
91            return MemoryType.NON_HEAP;
92        }
93    }
94
95    public MemoryUsage getUsage() {
96        return getUsage0();
97    }
98
99    public synchronized MemoryUsage getPeakUsage() {
100        // synchronized since resetPeakUsage may be resetting the peak usage
101        return getPeakUsage0();
102    }
103
104    public synchronized long getUsageThreshold() {
105        if (!isUsageThresholdSupported()) {
106            throw new UnsupportedOperationException(
107                "Usage threshold is not supported");
108        }
109        return usageThreshold;
110    }
111
112    public void setUsageThreshold(long newThreshold) {
113        if (!isUsageThresholdSupported()) {
114            throw new UnsupportedOperationException(
115                "Usage threshold is not supported");
116        }
117
118        Util.checkControlAccess();
119
120        MemoryUsage usage = getUsage0();
121        if (newThreshold < 0) {
122            throw new IllegalArgumentException(
123                "Invalid threshold: " + newThreshold);
124        }
125
126        if (usage.getMax() != -1 && newThreshold > usage.getMax()) {
127            throw new IllegalArgumentException(
128                "Invalid threshold: " + newThreshold +
129                " must be <= maxSize." +
130                " Committed = " + usage.getCommitted() +
131                " Max = " + usage.getMax());
132        }
133
134        synchronized (this) {
135            if (!usageSensorRegistered) {
136                // pass the sensor to VM to begin monitoring
137                usageSensorRegistered = true;
138                setPoolUsageSensor(usageSensor);
139            }
140            setUsageThreshold0(usageThreshold, newThreshold);
141            this.usageThreshold = newThreshold;
142        }
143    }
144
145    private synchronized MemoryManagerMXBean[] getMemoryManagers() {
146        if (managers == null) {
147            managers = getMemoryManagers0();
148        }
149        return managers;
150    }
151
152    public String[] getMemoryManagerNames() {
153        MemoryManagerMXBean[] mgrs = getMemoryManagers();
154
155        String[] names = new String[mgrs.length];
156        for (int i = 0; i < mgrs.length; i++) {
157            names[i] = mgrs[i].getName();
158        }
159        return names;
160    }
161
162    public void resetPeakUsage() {
163        Util.checkControlAccess();
164
165        synchronized (this) {
166            // synchronized since getPeakUsage may be called concurrently
167            resetPeakUsage0();
168        }
169    }
170
171    public boolean isUsageThresholdExceeded() {
172        if (!isUsageThresholdSupported()) {
173            throw new UnsupportedOperationException(
174                "Usage threshold is not supported");
175        }
176
177        // return false if usage threshold crossing checking is disabled
178        if (usageThreshold == 0) {
179            return false;
180        }
181
182        MemoryUsage u = getUsage0();
183        return (u.getUsed() >= usageThreshold ||
184                usageSensor.isOn());
185    }
186
187    public long getUsageThresholdCount() {
188        if (!isUsageThresholdSupported()) {
189            throw new UnsupportedOperationException(
190                "Usage threshold is not supported");
191        }
192
193        return usageSensor.getCount();
194    }
195
196    public boolean isUsageThresholdSupported() {
197        return usageThresholdSupported;
198    }
199
200    public synchronized long getCollectionUsageThreshold() {
201        if (!isCollectionUsageThresholdSupported()) {
202            throw new UnsupportedOperationException(
203                "CollectionUsage threshold is not supported");
204        }
205
206        return collectionThreshold;
207    }
208
209    public void setCollectionUsageThreshold(long newThreshold) {
210        if (!isCollectionUsageThresholdSupported()) {
211            throw new UnsupportedOperationException(
212                "CollectionUsage threshold is not supported");
213        }
214
215        Util.checkControlAccess();
216
217        MemoryUsage usage = getUsage0();
218        if (newThreshold < 0) {
219            throw new IllegalArgumentException(
220                "Invalid threshold: " + newThreshold);
221        }
222
223        if (usage.getMax() != -1 && newThreshold > usage.getMax()) {
224            throw new IllegalArgumentException(
225                "Invalid threshold: " + newThreshold +
226                     " > max (" + usage.getMax() + ").");
227        }
228
229        synchronized (this) {
230            if (!gcSensorRegistered) {
231                // pass the sensor to VM to begin monitoring
232                gcSensorRegistered = true;
233                setPoolCollectionSensor(gcSensor);
234            }
235            setCollectionThreshold0(collectionThreshold, newThreshold);
236            this.collectionThreshold = newThreshold;
237        }
238    }
239
240    public boolean isCollectionUsageThresholdExceeded() {
241        if (!isCollectionUsageThresholdSupported()) {
242            throw new UnsupportedOperationException(
243                "CollectionUsage threshold is not supported");
244        }
245
246        // return false if usage threshold crossing checking is disabled
247        if (collectionThreshold == 0) {
248            return false;
249        }
250
251        MemoryUsage u = getCollectionUsage0();
252        return (gcSensor.isOn() ||
253                (u != null && u.getUsed() >= collectionThreshold));
254    }
255
256    public long getCollectionUsageThresholdCount() {
257        if (!isCollectionUsageThresholdSupported()) {
258            throw new UnsupportedOperationException(
259                "CollectionUsage threshold is not supported");
260        }
261
262        return gcSensor.getCount();
263    }
264
265    public MemoryUsage getCollectionUsage() {
266        return getCollectionUsage0();
267    }
268
269    public boolean isCollectionUsageThresholdSupported() {
270        return collectionThresholdSupported;
271    }
272
273    // Native VM support
274    private native MemoryUsage getUsage0();
275    private native MemoryUsage getPeakUsage0();
276    private native MemoryUsage getCollectionUsage0();
277    private native void setUsageThreshold0(long current, long newThreshold);
278    private native void setCollectionThreshold0(long current, long newThreshold);
279    private native void resetPeakUsage0();
280    private native MemoryManagerMXBean[] getMemoryManagers0();
281    private native void setPoolUsageSensor(Sensor s);
282    private native void setPoolCollectionSensor(Sensor s);
283
284    // package private
285
286    /**
287     * PoolSensor will be triggered by the VM when the memory
288     * usage of a memory pool is crossing the usage threshold.
289     * The VM will not trigger this sensor in subsequent crossing
290     * unless the memory usage has returned below the threshold.
291     */
292    class PoolSensor extends Sensor {
293        MemoryPoolImpl pool;
294
295        PoolSensor(MemoryPoolImpl pool, String name) {
296            super(name);
297            this.pool = pool;
298        }
299        void triggerAction(MemoryUsage usage) {
300            // create and send notification
301            MemoryImpl.createNotification(MEMORY_THRESHOLD_EXCEEDED,
302                                          pool.getName(),
303                                          usage,
304                                          getCount());
305        }
306        void triggerAction() {
307            // do nothing
308        }
309        void clearAction() {
310            // do nothing
311        }
312    }
313
314    /**
315     * CollectionSensor will be triggered and cleared by the VM
316     * when the memory usage of a memory pool after GC is crossing
317     * the collection threshold.
318     * The VM will trigger this sensor in subsequent crossing
319     * regardless if the memory usage has changed siince the previous GC.
320     */
321    class CollectionSensor extends Sensor {
322        MemoryPoolImpl pool;
323        CollectionSensor(MemoryPoolImpl pool, String name) {
324            super(name);
325            this.pool = pool;
326        }
327        void triggerAction(MemoryUsage usage) {
328            MemoryImpl.createNotification(MEMORY_COLLECTION_THRESHOLD_EXCEEDED,
329                                          pool.getName(),
330                                          usage,
331                                          gcSensor.getCount());
332        }
333        void triggerAction() {
334            // do nothing
335        }
336        void clearAction() {
337            // do nothing
338        }
339    }
340
341    public ObjectName getObjectName() {
342        return Util.newObjectName(ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE, getName());
343    }
344
345}
346