java.lang.management

接口
异常
public interface MemoryPoolMXBean

内存池的管理接口。内存池表示由 Java 虚拟机管理的内存资源,由一个或多个内存管理器对内存池进行管理。

Java 虚拟机具有此接口的实现类的一个或多个实例。实现此接口的实例是 MXBean,可以通过调用 ManagementFactory.getMemoryPoolMXBeans() 方法或从平台 MBeanServer 方法获得。

MBeanServer 中惟一标识内存池的 MXBean 的 ObjectName 为:

java.lang:type=MemoryPool ,name= pool's name

内存类型

Java 虚拟机具有一个用于对象分配的堆,还包含用于方法区域和 Java 虚拟机执行的非堆内存。Java 虚拟机可以有一个或多个内存池。每个内存池表示一个内存区域,此内存区域可为以下类型之一:

内存使用量监视

内存池具有以下属性:

1. 内存使用量

getUsage() 方法提供了内存池当前使用量的估计数。对于垃圾回收内存池,已使用的内存包括由池中所有对象(包括 可到达 对象和 不可达到 对象)占用的内存。

通常,此方法是一个轻量操作,用于获取近似内存使用量。对于某些内存池(例如,当对象未连续打包时),此方法可能成为开销巨大的操作,要求进行计算以确定当前的内存使用量。如果是这样,实现应该加以注释。

2. 峰值内存使用量

Java 虚拟机会维护自虚拟机启动或者峰值重置以来的内存池峰值内存使用量。峰值内存使用量由 getPeakUsage() 方法返回,通过调用 resetPeakUsage() 方法可将其重置。

3. 使用量阈值

每个内存池都有一个可管理的属性,称为 使用量阈值,其默认值由 Java 虚拟机提供。此默认值与平台有关。可以通过 setUsageThreshold 方法设置使用量阈值。如果阈值设置为正数,将启用此内存池中的使用量阈值超过检查。如果使用率阈值设置为零,将禁用此内存池的使用量阈值超过检查。 isUsageThresholdSupported() 方法可用于确定是否支持此功能。

Java 虚拟机在其最恰当的时候(通常在垃圾回收时)会对内存池逐个进行使用量阈值超过检查。每个内存池均维护一个使用量阈值计数,每次 Java 虚拟机检测到内存池使用量超过阈值,此值都会加 1。

此可管理的使用量阈值属性设计用于以低开销监视内存使用量增加的趋势。使用量阈值可能不适合某些内存池。例如,生存期垃圾回收器是在很多 Java 虚拟机实现中都使用的一种常见的垃圾回收算法,它按照生存时间管理划分为两代或多代的对象。很多对象都分配在最新的一代(称为新生内存池)。新生内存池的设计使其很容易被填满,回收新生内存池将会释放其大部分内存空间,因为这种内存池包含了大多数生存时间短的对象,以及大多数在垃圾回收时不可到达的对象。在这种情况下,新生内存池不支持使用量阈值会更为合适。此外,如果在一个内存池中进行对象分配的开销很小(例如,只是原子指针交换),Java 虚拟机将可能不支持该内存池的使用量阈值,因为使用量阈值的开销比对象分配的开销大。

系统的内存使用量可以通过轮询阈值通知机制进行监视。

  1. 轮询

    通过调用所有内存池的 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();
           }
           

  2. 使用量阈值通知

    使用量阈值通知将由 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() 返回的当前使用量阈值计数进行比较,以确定是否出现了此类情况。

4. 回收使用量阈值

回收使用量阈值是一个可管理属性,仅适用于某些垃圾回收内存池。Java 虚拟机通过在垃圾回收时回收内存池中未使用的对象,完成了内存空间的回收工作之后,内存池中某些经过垃圾回收的字节仍在使用。回收使用量阈值允许为此字节数设置一个值,这样在超过该阈值的情况下,将由 MemoryMXBean 发出 回收使用量超过通知。此外, 回收使用量阈值计数将增加 1。

isCollectionUsageThresholdSupported() 方法可用于确定是否支持此功能。

Java 虚拟机按内存池执行回收使用量阈值检查。如果回收使用量阈值设置为正数,则将启用此检查。如果回收使用量阈值设置为零,将在此内存池上禁用此检查。默认值为零。Java 虚拟机将在垃圾回收时执行回收使用量阈值检查。

某些垃圾回收内存池可能选择不支持回收使用量阈值。例如,仅由持续并发垃圾回收器管理的内存池。在此内存池中,某个线程可以分配对象,而同时不使用的对象将由并发垃圾回收器进行回收。除非有定义良好的垃圾回收时间,该时间是检查内存使用量的最恰当时间,否则就不应该支持回收使用量阈值。

回收使用量阈值设计用于监视 Java 虚拟机进行内存空间回收工作之后的内存使用量。还可以采用与上述监视使用量阈值类似的方法,通过轮询和阈值通知机制监视回收使用量阈值。

从以下版本开始:
1.5
另请参见:
JMX Specification., 访问 MXBeans 的方式

方法摘要
 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 值。
 

方法详细信息

getName

String getName()
返回表示此内存池的名称。

返回:
此内存池的名称。

getType

MemoryType getType()
返回此内存池的类型。

MBeanServer 访问
MemoryType 的映射类型为 String,值为 MemoryType 的名称。

返回:
此内存池的类型。

getUsage

MemoryUsage getUsage()
返回此内存池的内存使用量的估计数。如果此内存池无效(即不再存在),此方法将返回 null

此方法请求 Java 虚拟机对此内存池的当前内存使用量进行最佳估算。对于某些内存池,此方法可能是开销很大的操作,需要进行计算以确定估计数。如果是这种情况,实现应该加以注释。

此方法设计用于监视系统内存使用量和检测低内存情况。

MBeanServer 访问
MemoryUsage 的映射类型为 CompositeData,具有 MemoryUsage 中指定的那些属性。

返回:
MemoryUsage 对象;或者,如果此内存池无效,则返回 null

getPeakUsage

MemoryUsage getPeakUsage()
返回自 Java 虚拟机启动以来或自峰值重置以来此内存池的峰值内存使用量。如果此内存池无效(即不再存在),此方法将返回 null

MBeanServer 访问
MemoryUsage 的映射类型为 CompositeData,具有 MemoryUsage 中指定的那些属性。

返回:
表示峰值内存使用量的 MemoryUsage 对象;或者,如果此内存池无效,则返回 null

resetPeakUsage

void resetPeakUsage()
将此内存池的峰值内存使用量统计重置为当前内存使用量。

抛出:
SecurityException - 如果存在安全管理器,且调用方不具有 ManagementPermission("control")。

isValid

boolean isValid()
测试此内存池在 Java 虚拟机中是否有效。一旦 Java 虚拟机将内存池从内存系统删除,该内存池就变为无效。

返回:
如果内存池在正在运行的 Java 虚拟机中有效,则返回 true;否则返回 false

getMemoryManagerNames

String[] getMemoryManagerNames()
返回管理此内存池的内存管理器的名称。每个内存池将由至少一个内存管理器进行管理。

返回:
String 对象的一个数组,其中每个对象都是管理此内存池的内存管理器的名称。

getUsageThreshold

long getUsageThreshold()
返回此内存池的使用量阈值(以字节为单位)。每个内存池都具有一个与平台有关的默认阈值。可以通过 setUsageThreshold 方法更改当前的使用量阈值。

返回:
此内存池的使用量阈值(以字节为单位)。
抛出:
UnsupportedOperationException - 如果此内存池不支持使用量阈值。
另请参见:
isUsageThresholdSupported()

setUsageThreshold

void setUsageThreshold(long threshold)
如果此内存池支持使用量阈值,则将此内存池的阈值设置为给定的 threshold 值。如果阈值设置为正数,将启用此内存池中的使用量阈值超过检查。如果设置为零,则将禁用使用量阈值超过检查。

参数:
threshold - 新阈值(以字节为单位)。必须为非负数。
抛出:
IllegalArgumentException - 如果 threshold 为负或大于此内存池的最大内存量(如果已定义)。
UnsupportedOperationException - 如果此内存池不支持使用量阈值。
SecurityException - 如果存在安全管理器,且调用方不具有 ManagementPermission("control")。
另请参见:
isUsageThresholdSupported(), 使用量阈值

isUsageThresholdExceeded

boolean isUsageThresholdExceeded()
测试此内存池的使用量是否达到或超过其使用量阈值。

返回:
如果此内存池的使用量达到或超过了阈值,则返回 true;否则返回 false
抛出:
UnsupportedOperationException - 如果此内存池不支持使用量阈值。

getUsageThresholdCount

long getUsageThresholdCount()
返回内存使用量超过其阈值的次数。

返回:
内存使用量超过其阈值的次数。
抛出:
UnsupportedOperationException - 如果此内存池不支持使用量阈值。

isUsageThresholdSupported

boolean isUsageThresholdSupported()
测试此内存池是否支持使用量阈值。

返回:
如果此内存池支持使用量阈值,则返回 true;否则返回 false

getCollectionUsageThreshold

long getCollectionUsageThreshold()
返回此内存池的回收使用量阈值(以字节为单位)。默认值为零。可以通过 setCollectionUsageThreshold 方法更改回收使用量阈值。

返回:
此内存池的回收使用量阈值(以字节为单位)。
抛出:
UnsupportedOperationException - 如果此内存池不支持回收使用量阈值。
另请参见:
isCollectionUsageThresholdSupported()

setCollectionUsageThreshold

void setCollectionUsageThreshold(long threhsold)
将此内存池的回收使用量阈值设置为给定的 threshold 值。当此阈值设置为正数时,Java 虚拟机将在对此内存池中不使用的对象进行了回收工作后,在最恰当的时间检查内存使用量。

如果阈值设置为正数,将启用此内存池中的回收使用量阈值超过检查。如果设置为零,则将禁用回收使用量阈值超过检查。

参数:
threhsold - 新的回收使用量阈值(以字节为单位)。必须为非负数。
抛出:
IllegalArgumentException - 如果 threshold 为负或大于此内存池的最大内存量(如果已定义)。
UnsupportedOperationException - 如果此内存池不支持回收使用量阈值。
SecurityException - 如果存在安全管理器,且调用方不具有 ManagementPermission("control")。
另请参见:
isCollectionUsageThresholdSupported(), 回收使用量阈值

isCollectionUsageThresholdExceeded

boolean isCollectionUsageThresholdExceeded()
测试在 Java 虚拟机最近一次回收工作之后,此内存池的内存使用量是否达到或超过了其回收使用量阈值。此方法不会请求 Java 虚拟机执行其正常自动内存管理之外的任何垃圾回收操作。

返回:
如果在最近的回收操作中,此内存池的使用量达到或超过了回收使用阈值,则返回 true;否则返回 false
抛出:
UnsupportedOperationException - 如果此内存池不支持使用量阈值。

getCollectionUsageThresholdCount

long getCollectionUsageThresholdCount()
返回 Java 虚拟机已检测到内存使用量达到或超过回收使用量阈值的次数。

返回:
内存使用量达到或超过回收使用量阈值的次数。
抛出:
UnsupportedOperationException - 如果此内存池不支持回收使用量阈值。
另请参见:
isCollectionUsageThresholdSupported()

getCollectionUsage

MemoryUsage getCollectionUsage()
返回 Java 虚拟机最近回收了此内存池中的不使用的对象之后的内存使用量。此方法不会请求 Java 虚拟机执行其正常的自动内存管理之外的任何垃圾回收操作。如果 Java 虚拟机不支持此方法,此方法将返回 null

MBeanServer 访问
MemoryUsage 的映射类型为 CompositeData,具有 MemoryUsage 中指定的那些属性。

返回:
表示 Java 虚拟机最近对不使用的对象进行了回收之后此内存池的内存使用量的 MemoryUsage;如果不支持此方法,则返回 null

isCollectionUsageThresholdSupported

boolean isCollectionUsageThresholdSupported()
测试此内存池是否支持回收使用量阈值。

返回:
如果此内存池支持回收使用量阈值,则返回 true;否则返回 false