1 /*
   2  * Copyright (c) 2018, Google 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package MyPackage;
  25 
  26 import java.util.ArrayList;
  27 import java.util.List;
  28 
  29 /** API for handling the underlying heap sampling monitoring system. */
  30 public class HeapMonitor {
  31   private static int[][] arrays;
  32 
  33   static {
  34     try {
  35       System.loadLibrary("HeapMonitor");
  36     } catch (UnsatisfiedLinkError ule) {
  37       System.err.println("Could not load HeapMonitor library");
  38       System.err.println("java.library.path: " + System.getProperty("java.library.path"));
  39       throw ule;
  40     }
  41   }
  42 
  43   /** Enable heap monitoring sampling with default value for rate. */
  44   public static void enableSamplingRate() {
  45     setSamplingRate(1 << 19);
  46   }
  47 
  48   public static void disableSamplingRate() {
  49     setSamplingRate(0);
  50   }
  51 
  52   /** Set a specific sampling rate, 0 turns off sampling. */
  53   public native static void setSamplingRate(int rate);
  54 
  55   public native static void enableSamplingEvents();
  56   public native static void disableSamplingEvents();
  57 
  58   /**
  59    * Allocate memory but first create a stack trace of a particular depth.
  60    *
  61    * @return list of frames for the allocation.
  62    */
  63   public static List<Frame> allocate(int depth) {
  64     List<Frame> frames = new ArrayList<Frame>();
  65     if (depth > 1) {
  66       createStackDepth(depth - 1, frames);
  67       frames.add(new Frame("allocate", "(I)Ljava/util/List;", "HeapMonitor.java", 61));
  68     } else {
  69       actuallyAllocate();
  70       frames.add(new Frame("actuallyAllocate", "()I", "HeapMonitor.java", 126));
  71       frames.add(new Frame("allocate", "(I)Ljava/util/List;", "HeapMonitor.java", 64));
  72     }
  73     return frames;
  74   }
  75 
  76   /**
  77    * Allocate memory but first create a stack trace.
  78    *
  79    * @return list of frames for the allocation.
  80    */
  81   public static List<Frame> allocate() {
  82     int sum = 0;
  83     List<Frame> frames = new ArrayList<Frame>();
  84     allocate(frames);
  85     frames.add(new Frame("allocate", "()Ljava/util/List;", "HeapMonitor.java", 79));
  86     return frames;
  87   }
  88 
  89   private static void createStackDepth(int depth, List<Frame> frames) {
  90     if (depth > 1) {
  91       createStackDepth(depth - 1, frames);
  92       frames.add(new Frame("createStackDepth", "(ILjava/util/List;)V", "HeapMonitor.java", 86));
  93     } else {
  94       allocate(frames);
  95       frames.add(new Frame("createStackDepth", "(ILjava/util/List;)V", "HeapMonitor.java", 89));
  96     }
  97   }
  98 
  99   private static void allocate(List<Frame> frames) {
 100     int sum = 0;
 101     for (int j = 0; j < 1000; j++) {
 102       sum += actuallyAllocate();
 103     }
 104     frames.add(new Frame("actuallyAllocate", "()I", "HeapMonitor.java", 124));
 105     frames.add(new Frame("allocate", "(Ljava/util/List;)V", "HeapMonitor.java", 97));
 106   }
 107 
 108   public static List<Frame> repeatAllocate(int max) {
 109     List<Frame> frames = null;
 110     for (int i = 0; i < max; i++) {
 111       frames = allocate();
 112     }
 113     frames.add(new Frame("repeatAllocate", "(I)Ljava/util/List;", "HeapMonitor.java", 106));
 114     return frames;
 115   }
 116 
 117   private static int actuallyAllocate() {
 118     int sum = 0;
 119 
 120     // Let us assume that a 1-element array is 24 bytes of memory and we want
 121     // 2MB allocated.
 122     int iterations = (1 << 19) / 6;
 123 
 124     if (arrays == null) {
 125       arrays = new int[iterations][];
 126     }
 127 
 128     for (int i = 0; i < iterations; i++) {
 129       int tmp[] = new int[1];
 130       // Force it to be kept and, at the same time, wipe out any previous data.
 131       arrays[i] = tmp;
 132       sum += arrays[0][0];
 133     }
 134     return sum;
 135   }
 136 
 137   /** Remove the reference to the global array to free data at the next GC. */
 138   public static void freeStorage() {
 139     arrays = null;
 140   }
 141 
 142   public native static boolean obtainedEvents(Frame[] frames);
 143   public native static boolean eventStorageIsEmpty();
 144   public native static void resetEventStorage();
 145 }