1 package org.unicode.cldr.util; 2 3 import java.text.CharacterIterator; 4 import java.text.StringCharacterIterator; 5 6 public class MemoryHelper { 7 8 /** 9 * Get the amount of memory still available for us to allocate, including not only freeMemory 10 * but also maxMemory - totalMemory 11 * 12 * <p>https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Runtime.html#freeMemory() 13 * 14 * <p>Generally: freeMemory <= totalMemory <= maxMemory 15 * 16 * @param callerId a string identifying the caller, used in log if verbose 17 * @param verbose if true, log the stats 18 * @return the available memory, in bytes 19 */ availableMemory(String callerId, boolean verbose)20 public static synchronized long availableMemory(String callerId, boolean verbose) { 21 final Runtime r = Runtime.getRuntime(); 22 long freeMem = r.freeMemory(); 23 long maxMem = r.maxMemory(); 24 long totalMem = r.totalMemory(); 25 if (freeMem > totalMem || totalMem > maxMem) { 26 log(callerId, "Values returned by Runtime violate assumptions!"); 27 verbose = true; 28 } 29 long availMem = freeMem + maxMem - totalMem; 30 if (verbose) { 31 log( 32 callerId, 33 "Available memory: " 34 + humanReadableByteCountSI(availMem) 35 + "; free: " 36 + humanReadableByteCountSI(freeMem) 37 + "; max: " 38 + humanReadableByteCountSI(maxMem) 39 + "; total: " 40 + humanReadableByteCountSI(totalMem)); 41 } 42 return availMem; 43 } 44 log(String callerId, String message)45 private static void log(String callerId, String message) { 46 System.out.println("MemoryHelper[" + callerId + "]: " + message); 47 } 48 49 /** 50 * Convert a byte count to a human readable string Use SI (1 k = 1,000), not Binary (1 K = 51 * 1,024) 52 * 53 * @param bytes the number such as 1234567890 54 * @return the formatted string such as "1.2 GB" 55 * <p>Source: 56 * https://programming.guide/java/formatting-byte-size-to-human-readable-format.html 57 */ humanReadableByteCountSI(long bytes)58 public static String humanReadableByteCountSI(long bytes) { 59 if (-1000 < bytes && bytes < 1000) { 60 return bytes + " B"; 61 } 62 CharacterIterator ci = new StringCharacterIterator("kMGTPE"); 63 while (bytes <= -999_950 || bytes >= 999_950) { 64 bytes /= 1000; 65 ci.next(); 66 } 67 return String.format("%.1f %cB", bytes / 1000.0, ci.current()); 68 } 69 } 70