public interface MemoryPoolMXBean
内存池的管理接口。内存池表示由 Java 虚拟机管理的内存资源,由一个或多个内存管理器
对内存池进行管理。
Java 虚拟机具有此接口的实现类的一个或多个实例。实现此接口的实例是 MXBean,可以通过调用 ManagementFactory.getMemoryPoolMXBeans()
方法或从平台 MBeanServer
方法获得。
在 MBeanServer 中惟一标识内存池的 MXBean 的 ObjectName 为:
java.lang:type=MemoryPool
,name=
pool's name
Java 虚拟机具有一个用于对象分配的堆,还包含用于方法区域和 Java 虚拟机执行的非堆内存。Java 虚拟机可以有一个或多个内存池。每个内存池表示一个内存区域,此内存区域可为以下类型之一:
getUsage()
方法提供了内存池当前使用量的估计数。对于垃圾回收内存池,已使用的内存包括由池中所有对象(包括
可到达 对象和
不可达到 对象)占用的内存。
通常,此方法是一个轻量操作,用于获取近似内存使用量。对于某些内存池(例如,当对象未连续打包时),此方法可能成为开销巨大的操作,要求进行计算以确定当前的内存使用量。如果是这样,实现应该加以注释。
getPeakUsage()
方法返回,通过调用
resetPeakUsage()
方法可将其重置。
setUsageThreshold
方法设置使用量阈值。如果阈值设置为正数,将启用此内存池中的使用量阈值超过检查。如果使用率阈值设置为零,将禁用此内存池的使用量阈值超过检查。
isUsageThresholdSupported()
方法可用于确定是否支持此功能。
Java 虚拟机在其最恰当的时候(通常在垃圾回收时)会对内存池逐个进行使用量阈值超过检查。每个内存池均维护一个使用量阈值计数
,每次 Java 虚拟机检测到内存池使用量超过阈值,此值都会加 1。
此可管理的使用量阈值属性设计用于以低开销监视内存使用量增加的趋势。使用量阈值可能不适合某些内存池。例如,生存期垃圾回收器是在很多 Java 虚拟机实现中都使用的一种常见的垃圾回收算法,它按照生存时间管理划分为两代或多代的对象。很多对象都分配在最新的一代(称为新生内存池)。新生内存池的设计使其很容易被填满,回收新生内存池将会释放其大部分内存空间,因为这种内存池包含了大多数生存时间短的对象,以及大多数在垃圾回收时不可到达的对象。在这种情况下,新生内存池不支持使用量阈值会更为合适。此外,如果在一个内存池中进行对象分配的开销很小(例如,只是原子指针交换),Java 虚拟机将可能不支持该内存池的使用量阈值,因为使用量阈值的开销比对象分配的开销大。
通过调用所有内存池的 getUsage()
方法或调用支持使用量阈值的内存池的 isUsageThresholdExceeded()
方法,应用程序可以持续监视其内存使用量。以下的示例代码具有一个专门用于任务分配和处理的线程。每隔一段时间,它将根据其内存使用量确定是否应当接受和处理新任务。如果内存使用量超过了其使用量阈值,它会将所有未处理的任务重新分配给其他 VM 并停止接受新任务,直到内存使用量低于其使用量阈值。
// Assume the usage threshold is supported for this pool. // Set the threshold to myThreshold above which no new tasks // should be taken. pool.setUsageThreshold(myThreshold); .... boolean lowMemory = false; while (true) { if (pool.isUsageThresholdExceeded()) { // potential low memory, so redistribute tasks to other VMs lowMemory = true; redistributeTasks(); // stop receiving new tasks stopReceivingTasks(); } else { if (lowMemory) { // resume receiving tasks lowMemory = false; resumeReceivingTasks(); } // processing outstanding task ... } // sleep for sometime try { Thread.sleep(sometime); } catch (InterruptedException e) { ... } }
getUsageThresholdCount()
方法返回的使用量阈值计数可用于确定在两次轮询之间返回的内存使用量是否低于阈值。 以下是另一个示例,该示例在内存池出现内存空间不足时将采取一些操作,并会忽略在操作处理期间的内存使用量变化。
// Assume the usage threshold is supported for this pool. // Set the threshold to myThreshold which determines if // the application will take some action under low memory condition. pool.setUsageThreshold(myThreshold); int prevCrossingCount = 0; while (true) { // A busy loop to detect when the memory usage // has exceeded the threshold. while (!pool.isUsageThresholdExceeded() || pool.getUsageThresholdCount() == prevCrossingCount) { try { Thread.sleep(sometime) } catch (InterruptException e) { .... } } // Do some processing such as check for memory usage // and issue a warning .... // Gets the current threshold count. The busy loop will then // ignore any crossing of threshold happens during the processing. prevCrossingCount = pool.getUsageThresholdCount(); }
使用量阈值通知将由 MemoryMXBean
发出。当 Java 虚拟机检测到内存池的内存使用量达到或超过其内存使用量阈值时,虚拟机将触发 MemoryMXBean ,发出使用量阈值超过通知
。直到使用量降低到阈值以下,然后再次超过了阈值,才会再次生成使用量阈值超过通知。
以下示例代码实现了与以上示例相同的逻辑,但使用了使用量阈值通知机制(而非轮询)来检测低内存情况。在此示例代码中,接收到通知时,通知侦听器将通知另一个线程执行实际的操作,如重新分配未处理的任务、停止接受任务,或恢复接受任务等。handleNotification 方法应该设计为完成很少的工作,且无延迟地返回,以避免导致交付后续通知时出现延迟。耗时的操作应该使用独立的线程来执行。通知侦听器可以由多个线程并发调用,因此侦听器执行的任务应该进行适当地同步。
class MyListener implements javax.management.NotificationListener { public void handleNotification(Notification notification, Object handback) { String notifType = notification.getType(); if (notifType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) { // potential low memory, notify another thread // to redistribute outstanding tasks to other VMs // and stop receiving new tasks. lowMemory = true; notifyAnotherThread(lowMemory); } } } // Register MyListener with MemoryMXBean MemoryMXBean mbean = ManagementFactory.getMemoryMXBean(); NotificationEmitter emitter = (NotificationEmitter) mbean; MyListener listener = new MyListener(); emitter.addNotificationListener(listener, null, null); // Assume this pool supports a usage threshold. // Set the threshold to myThreshold above which no new tasks // should be taken. pool.setUsageThreshold(myThreshold); // Usage threshold detection is enabled and notification will be // handled by MyListener. Continue for other processing. ....
无法保证 MemoryMXBean 何时发出阈值通知和交付通知。当调用通知侦听器时,内存池的内存使用量可能已经多次超过使用量阈值。MemoryNotificationInfo.getCount()
方法将返回构造通知时内存使用量已超过使用量阈值的次数。可以将此值与 getUsageThresholdCount()
返回的当前使用量阈值计数进行比较,以确定是否出现了此类情况。
MemoryMXBean
发出
回收使用量超过通知
。此外,
回收使用量阈值计数
将增加 1。
isCollectionUsageThresholdSupported()
方法可用于确定是否支持此功能。
Java 虚拟机按内存池执行回收使用量阈值检查。如果回收使用量阈值设置为正数,则将启用此检查。如果回收使用量阈值设置为零,将在此内存池上禁用此检查。默认值为零。Java 虚拟机将在垃圾回收时执行回收使用量阈值检查。
某些垃圾回收内存池可能选择不支持回收使用量阈值。例如,仅由持续并发垃圾回收器管理的内存池。在此内存池中,某个线程可以分配对象,而同时不使用的对象将由并发垃圾回收器进行回收。除非有定义良好的垃圾回收时间,该时间是检查内存使用量的最恰当时间,否则就不应该支持回收使用量阈值。
回收使用量阈值设计用于监视 Java 虚拟机进行内存空间回收工作之后的内存使用量。还可以采用与上述监视使用量阈值类似的方法,通过轮询和阈值通知机制监视回收使用量阈值。
方法摘要 | |
---|---|
MemoryUsage |
getCollectionUsage() 返回 Java 虚拟机最近回收了此内存池中的不使用的对象之后的内存使用量。 |
long |
getCollectionUsageThreshold() 返回此内存池的回收使用量阈值(以字节为单位)。 |
long |
getCollectionUsageThresholdCount() 返回 Java 虚拟机已检测到内存使用量达到或超过回收使用量阈值的次数。 |
String[] |
getMemoryManagerNames() 返回管理此内存池的内存管理器的名称。 |
String |
getName() 返回表示此内存池的名称。 |
MemoryUsage |
getPeakUsage() 返回自 Java 虚拟机启动以来或自峰值重置以来此内存池的峰值内存使用量。 |
MemoryType |
getType() 返回此内存池的类型。 |
MemoryUsage |
getUsage() 返回此内存池的内存使用量的估计数。 |
long |
getUsageThreshold() 返回此内存池的使用量阈值(以字节为单位)。 |
long |
getUsageThresholdCount() 返回内存使用量超过其阈值的次数。 |
boolean |
isCollectionUsageThresholdExceeded() 测试在 Java 虚拟机最近一次回收工作之后,此内存池的内存使用量是否达到或超过了其回收使用量阈值。 |
boolean |
isCollectionUsageThresholdSupported() 测试此内存池是否支持回收使用量阈值。 |
boolean |
isUsageThresholdExceeded() 测试此内存池的使用量是否达到或超过其使用量阈值。 |
boolean |
isUsageThresholdSupported() 测试此内存池是否支持使用量阈值。 |
boolean |
isValid() 测试此内存池在 Java 虚拟机中是否有效。 |
void |
resetPeakUsage() 将此内存池的峰值内存使用量统计重置为当前内存使用量。 |
void |
setCollectionUsageThreshold(long threhsold) 将此内存池的回收使用量阈值设置为给定的 threshold 值。 |
void |
setUsageThreshold(long threshold) 如果此内存池支持使用量阈值,则将此内存池的阈值设置为给定的 threshold 值。 |
方法详细信息 |
---|
String getName()
MemoryType getType()
MBeanServer 访问:
MemoryType 的映射类型为 String,值为 MemoryType 的名称。
MemoryUsage getUsage()
此方法请求 Java 虚拟机对此内存池的当前内存使用量进行最佳估算。对于某些内存池,此方法可能是开销很大的操作,需要进行计算以确定估计数。如果是这种情况,实现应该加以注释。
此方法设计用于监视系统内存使用量和检测低内存情况。
MBeanServer 访问:
MemoryUsage 的映射类型为 CompositeData,具有 MemoryUsage
中指定的那些属性。
MemoryUsage
对象;或者,如果此内存池无效,则返回
null。
MemoryUsage getPeakUsage()
MBeanServer 访问:
MemoryUsage 的映射类型为 CompositeData,具有 MemoryUsage
中指定的那些属性。
MemoryUsage
对象;或者,如果此内存池无效,则返回
null。
void resetPeakUsage()
SecurityException
- 如果存在安全管理器,且调用方不具有 ManagementPermission("control")。
boolean isValid()
String[] getMemoryManagerNames()
long getUsageThreshold()
setUsageThreshold
方法更改当前的使用量阈值。
UnsupportedOperationException
- 如果此内存池不支持使用量阈值。
isUsageThresholdSupported()
void setUsageThreshold(long threshold)
threshold
- 新阈值(以字节为单位)。必须为非负数。
IllegalArgumentException
- 如果
threshold 为负或大于此内存池的最大内存量(如果已定义)。
UnsupportedOperationException
- 如果此内存池不支持使用量阈值。
SecurityException
- 如果存在安全管理器,且调用方不具有 ManagementPermission("control")。
isUsageThresholdSupported()
,
使用量阈值
boolean isUsageThresholdExceeded()
UnsupportedOperationException
- 如果此内存池不支持使用量阈值。
long getUsageThresholdCount()
UnsupportedOperationException
- 如果此内存池不支持使用量阈值。
boolean isUsageThresholdSupported()
long getCollectionUsageThreshold()
setCollectionUsageThreshold
方法更改回收使用量阈值。
UnsupportedOperationException
- 如果此内存池不支持回收使用量阈值。
isCollectionUsageThresholdSupported()
void setCollectionUsageThreshold(long threhsold)
如果阈值设置为正数,将启用此内存池中的回收使用量阈值超过检查。如果设置为零,则将禁用回收使用量阈值超过检查。
threhsold
- 新的回收使用量阈值(以字节为单位)。必须为非负数。
IllegalArgumentException
- 如果
threshold 为负或大于此内存池的最大内存量(如果已定义)。
UnsupportedOperationException
- 如果此内存池不支持回收使用量阈值。
SecurityException
- 如果存在安全管理器,且调用方不具有 ManagementPermission("control")。
isCollectionUsageThresholdSupported()
,
回收使用量阈值
boolean isCollectionUsageThresholdExceeded()
UnsupportedOperationException
- 如果此内存池不支持使用量阈值。
long getCollectionUsageThresholdCount()
UnsupportedOperationException
- 如果此内存池不支持回收使用量阈值。
isCollectionUsageThresholdSupported()
MemoryUsage getCollectionUsage()
MBeanServer 访问:
MemoryUsage 的映射类型为 CompositeData,具有 MemoryUsage
中指定的那些属性。
MemoryUsage
;如果不支持此方法,则返回
null。
boolean isCollectionUsageThresholdSupported()