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