1 /* 2 * Copyright (c) 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. 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 package utils; 24 25 import java.lang.management.ManagementFactory; 26 import java.lang.management.MemoryMXBean; 27 import java.lang.management.MemoryPoolMXBean; 28 import java.lang.management.MemoryUsage; 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * This is an class used to allocate specified amount of metaspace and heap. 34 */ 35 public class GarbageProducer { 36 37 // Uses fixed small objects to avoid Humongous objects allocation with G1 GC. 38 private static final int MEMORY_CHUNK = 2048; 39 40 public static List<Object> allocatedMetaspace; 41 public static List<Object> allocatedMemory; 42 43 private final MemoryMXBean memoryMXBean; 44 private final float targetMemoryUsagePercent; 45 private final long targetMemoryUsage; 46 47 /** 48 * @param targetMemoryUsagePercent how many percent of metaspace and heap to 49 * allocate 50 */ GarbageProducer(float targetMemoryUsagePercent)51 public GarbageProducer(float targetMemoryUsagePercent) { 52 memoryMXBean = ManagementFactory.getMemoryMXBean(); 53 this.targetMemoryUsagePercent = targetMemoryUsagePercent; 54 targetMemoryUsage = (long) (memoryMXBean.getHeapMemoryUsage().getMax() * targetMemoryUsagePercent); 55 } 56 57 /** 58 * Allocates heap and metaspace upon exit targetMemoryUsagePercent percents 59 * of heap and metaspace have been consumed. 60 */ allocateMetaspaceAndHeap()61 public void allocateMetaspaceAndHeap() { 62 // Metaspace should be filled before Java Heap to prevent unexpected OOME 63 // in the Java Heap while filling Metaspace 64 allocatedMetaspace = eatMetaspace(targetMemoryUsagePercent); 65 allocatedMemory = allocateGarbage(targetMemoryUsage); 66 } 67 eatMetaspace(float targetUsage)68 private List<Object> eatMetaspace(float targetUsage) { 69 List<Object> list = new ArrayList<>(); 70 MemoryPoolMXBean metaspacePool = getMatchedMemoryPool(".*Metaspace.*"); 71 float currentUsage; 72 GeneratedClassProducer gp = new GeneratedClassProducer(); 73 do { 74 try { 75 list.add(gp.create(0)); 76 } catch (OutOfMemoryError oome) { 77 list = null; 78 throw new RuntimeException("Unexpected OOME '" + oome.getMessage() + "' while eating " + targetUsage + " of Metaspace."); 79 } 80 MemoryUsage memoryUsage = metaspacePool.getUsage(); 81 currentUsage = (((float) memoryUsage.getUsed()) / memoryUsage.getMax()); 82 } while (currentUsage < targetUsage); 83 return list; 84 } 85 getMatchedMemoryPool(String patternPoolName)86 private MemoryPoolMXBean getMatchedMemoryPool(String patternPoolName) { 87 return ManagementFactory.getMemoryPoolMXBeans().stream() 88 .filter(bean -> bean.getName().matches(patternPoolName)) 89 .findFirst() 90 .orElseThrow(() -> new RuntimeException("Cannot find '" + patternPoolName + "' memory pool.")); 91 } 92 allocateGarbage(long targetMemoryUsage)93 private List<Object> allocateGarbage(long targetMemoryUsage) { 94 List<Object> list = new ArrayList<>(); 95 do { 96 try { 97 list.add(new byte[MEMORY_CHUNK]); 98 } catch (OutOfMemoryError e) { 99 list = null; 100 throw new RuntimeException("Unexpected OOME '" + e.getMessage() + "'"); 101 } 102 } while (memoryMXBean.getHeapMemoryUsage().getUsed() < targetMemoryUsage); 103 return list; 104 } 105 106 /** 107 * Returns allocation rate for old gen based on appropriate MemoryPoolMXBean 108 * memory usage. 109 * 110 * @return allocation rate 111 */ getOldGenAllocationRatio()112 public float getOldGenAllocationRatio() { 113 MemoryPoolMXBean oldGenBean = getMatchedMemoryPool(".*Old.*|.*Tenured.*"); 114 MemoryUsage usage = oldGenBean.getUsage(); 115 System.out.format("Memory usage for %1s.\n", oldGenBean.getName()); 116 System.out.format("Used: %1d\n", usage.getUsed()); 117 System.out.format("Commited: %1d\n", usage.getCommitted()); 118 System.out.format("Max: %1d\n", usage.getMax()); 119 return ((float) usage.getUsed()) / usage.getCommitted(); 120 } 121 } 122