Package org.xmlBlaster.util.admin.extern

Source Code of org.xmlBlaster.util.admin.extern.LowMemoryDetector

/*------------------------------------------------------------------------------
Name:      LowMemoryDetector.java
Project:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
Usage:     java -Xms1M -Xmx2M -Dcom.sun.management.jmxremote -Djava.util.logging.config.file=testlog.properties org.xmlBlaster.util.admin.extern.LowMemoryDetector
------------------------------------------------------------------------------*/
package org.xmlBlaster.util.admin.extern;

import javax.management.ObjectName;
import javax.management.ObjectInstance;
import javax.management.QueryExp;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.Notification;
import javax.management.NotificationEmitter;

// JDK 1.5
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryNotificationInfo;
import javax.management.NotificationListener;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.MemoryType;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

// Needed only for DefaultLowMemoryListener
import org.xmlBlaster.engine.RequestBroker;
import org.xmlBlaster.util.Global;

/**
* Get notification when heap memory usage exceeds 90%.
* Configuration:
* <pre>
-xmlBlaster/jmx/observeLowMemory       Write a log error when 90% of the JVM memory is used (JDK >= 1.5) [true]
-xmlBlaster/jmx/memoryThresholdFactor  Configure the log error memory threshhold (defaults to 90%) (JDK >= 1.5) [0.9]
-xmlBlaster/jmx/exitOnMemoryThreshold  If true xmlBlaster stops if the memoryThresholdFactor is reached (JDK >= 1.5) [false]
* </pre>
* @since JDK 1.5 and xmlBlaster 1.0.7
* @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>
*/
public class LowMemoryDetector {
   private final static Logger log = Logger.getLogger(LowMemoryDetector.class.getName());
   private MBeanServer mbeanServer;
   private MemoryPoolMXBean pool;
   private double thresholdFactor;

   /**
    * Access the max available RAM for this JVM.
    * You can increase it with 'java -Xmx256M ...'
    * @return bytes
    */
   public static long maxJvmMemory() {
       MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
       MemoryUsage usage = mbean.getHeapMemoryUsage() ;
       return usage.getMax();
   }

   public MBeanServer getMBeanServer() {
      return this.mbeanServer;
   }

   /**
    * Default ctor for 90% threshold and registered DefaultLowMemoryListener.
    */
   public LowMemoryDetector() {
      this((float)0.9);
      register(new DefaultLowMemoryListener(this));
   }

   /**
    * @param thresholdFactor Use typically 0.9, if 90% of heap is used up the
    * listener is triggered
    */
   public LowMemoryDetector(float thresholdFactor) {
      this.thresholdFactor = thresholdFactor;
      // http://java.sun.com/j2se/1.5.0/docs/api/java/lang/management/MemoryPoolMXBean.html
      this.mbeanServer = MBeanServerFactory.createMBeanServer();//("org.xmlBlaster");

      List list = ManagementFactory.getMemoryPoolMXBeans();
      Iterator it = list.iterator();
      while (it.hasNext()) {
         MemoryPoolMXBean tmpPool = (MemoryPoolMXBean)it.next();
         if (tmpPool.isUsageThresholdSupported() && tmpPool.getType().equals(MemoryType.HEAP)) {
            this.pool = tmpPool;
            // "Tenured Gen" = pool.getName()
            long myThreshold = (long)(this.thresholdFactor * (double)this.pool.getUsage().getMax()); //getCommitted());
            this.pool.setUsageThreshold(myThreshold);
            //System.out.println("Adding maxJvmMemory=" + maxJvmMemory() +
            //      ", committed for heap=" + this.pool.getUsage().getCommitted() +
            //      ", max for heap=" + this.pool.getUsage().getMax() +
            //      ", used threshold=" + this.pool.getUsageThreshold());
            break;
         }
      }

      register(new DefaultLowMemoryListener(this));
   }

   /**
    * Register your low memory listener.
    */
   public void register(NotificationListener listener) {
      if (this.pool != null) {
         // register for notification ...
         MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
         NotificationEmitter emitter = (NotificationEmitter) mbean;
         emitter.addNotificationListener(listener, null, this.pool);
      }
   }

   /**
    * Tester: java -Xms2M -Xmx3M -Dcom.sun.management.jmxremote -DxmlBlaster/jmx/exitOnMemoryThreshold=true org.xmlBlaster.util.admin.extern.LowMemoryDetector
    */
   public static void main(String[] args) throws java.io.IOException {
     
      LowMemoryDetector mem = new LowMemoryDetector((float)0.9);
      mem.register(new DefaultLowMemoryListener(mem));

      ArrayList list = new ArrayList();
      System.out.println("Hit a key to start");
      System.in.read();
      int chunkSize = 100000;
      try {
         for (int i=0; i<1000; i++) {
            System.out.println("Hit a key to allocate next " + chunkSize + " bytes");
            System.in.read();
            System.out.println("Adding another junk " + chunkSize);
            byte[] buffer = new byte[chunkSize];
            list.add(buffer);
         }
      }
      catch(java.lang.OutOfMemoryError e) {
         System.out.println("OOOOO: " + e.toString());
         System.in.read();
      }
      System.out.println("DONE, hit a key to finish");
      System.in.read();
   }
}

   /**
    * The default handler just logs the situation or exits if configured. 
    */
   class DefaultLowMemoryListener implements NotificationListener {
      private final static Logger log = Logger.getLogger(DefaultLowMemoryListener.class.getName());
      boolean exitOnThreshold;
      MBeanServer mbeanServer;

      public DefaultLowMemoryListener(LowMemoryDetector lowMemoryDetector) {
         this.exitOnThreshold = Global.instance().getProperty().get("xmlBlaster/jmx/exitOnMemoryThreshold", this.exitOnThreshold);
         this.mbeanServer = lowMemoryDetector.getMBeanServer();
      }

      /**
       * Called when memory threshold is reached.
       */
      public void handleNotification(Notification notification, Object handback)  {
         try {
            String notifType = notification.getType();
            if (!notifType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED))
               return;

            MemoryPoolMXBean pool = (MemoryPoolMXBean)handback;

            int numTries = 5;
            for (int i=0; i<numTries; i++) {
               // Memory is low! maxJvmMemory=8.323 MBytes, max for heap=7.340 MBytes, otherMem=983040, threshold reached=6.606 MBytes,
               // Runtime.totalMemory=8323072, Runtime.freeMemory=1461904, usedMem=6.861 MBytes
               if (log.isLoggable(Level.FINE))
                  log.fine(
                  "Memory is low! maxJvmMemory=" + Global.byteString(LowMemoryDetector.maxJvmMemory()) +
                  ", max for heap=" + Global.byteString(pool.getUsage().getMax()) +
                  ", otherMem=" + Global.byteString(LowMemoryDetector.maxJvmMemory() - pool.getUsage().getMax()) // 8.323-7.340=0.983
                  ", threshold reached=" + Global.byteString(pool.getUsageThreshold()) +
                  ", Runtime.totalMemory=" + Global.byteString(Runtime.getRuntime().totalMemory()) +
                  ", Runtime.freeMemory=" + Global.byteString(Runtime.getRuntime().freeMemory()) +
                  ", usedMem=" + Global.byteString(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));

               System.gc();
               try { Thread.sleep(1); } catch (Exception e) {}

               long usedMem = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
               if (usedMem < pool.getUsageThreshold()) {
                  if (log.isLoggable(Level.FINE))
                     log.fine("Low memory: Nothing to do, the garbage collector has handled it usedMem=" + Global.byteString(usedMem) + " threshold=" + Global.byteString(pool.getUsageThreshold()));
                  return// Nothing to do, the garbage collector has handled it
               }
            }

            long usedMem = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());

            //Memory is low! maxJvmMemory=8.323 MBytes, committed for heap=7.340 MBytes, max for heap=7.340 MBytes,
            //threshold reached=6.606 MBytes, currently used=7.595 MBytes, count=2.
            //Physical RAM size is 1.060 GBytes, this JVM may use max 8.323 MBytes and max 1024 file descriptors
            log.severe("Memory is low! maxJvmMemory=" + Global.byteString(LowMemoryDetector.maxJvmMemory()) +
               //", committed for heap=" + Global.byteString(pool.getUsage().getCommitted()) +
               ", max for heap=" + Global.byteString(pool.getUsage().getMax()) +
               ", threshold reached=" + Global.byteString(pool.getUsageThreshold()) +
               ", currently used=" + Global.byteString(usedMem) +
               ", count=" + pool.getUsageThresholdCount() +
               ". Physical RAM size is " + Global.byteString(Global.totalPhysicalMemorySize) + "," +
               " this JVM may use max " + Global.byteString(Global.heapMemoryUsage) +
               " and max " + Global.maxFileDescriptorCount + " file descriptors");
            if (this.exitOnThreshold) {
               System.gc();
               try { Thread.sleep(1); } catch (Exception e) {}
               System.gc();
               try { Thread.sleep(1); } catch (Exception e) {}
               usedMem = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
               if (usedMem > pool.getUsageThreshold()) {
                  log.severe("Exiting now because of low memory (see '-xmlBlaster/jmx/exitOnMemoryThreshold true'");
                  System.exit(-9);
               }
               log.info("Garbage collected to usedMem=" + Global.byteString(usedMem) + ", we continue");
            }
         }
         catch (Throwable e) {
            e.printStackTrace();
         }
      }
   } // class DefaultLowMemoryListener

TOP

Related Classes of org.xmlBlaster.util.admin.extern.LowMemoryDetector

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.