JAL-3477 New sensible default decisions on memory, and new jvmmemmax setting for...
[jalview.git] / src / jalview / bin / MemorySetting.java
1 package jalview.bin;
2
3 public class MemorySetting
4 {
5   public static final long leaveFreeMinMemory = 536870912; // 0.5 GB
6
7   public static final long applicationMinMemory = 536870912; // 0.5 GB
8
9   private final static int maxHeapSizePerCentDefault = 90;
10
11   public final static String maxHeapSizePerCentProperty = "jvmmempc";
12
13   private final static long maxHeapSizeDefault = 34359738368L; // 32GB
14
15   public final static String maxHeapSizeProperty = "jvmmemmax";
16
17   public static long getMemorySetting()
18   {
19     return getMemorySetting(null, null);
20   }
21
22   public static long getMemorySetting(String jvmmemmaxString,
23           String jvmmempcString)
24   {
25     // actual Xmx value-to-be
26     long maxMemLong = -1;
27
28     // get (absolute) jvmmaxmem setting
29     long memmax = maxHeapSizeDefault;
30     String jvmmemmaxorig = jvmmemmaxString;
31     if (jvmmemmaxorig == null)
32     {
33       jvmmemmaxorig = System.getProperty(maxHeapSizeProperty);
34     }
35     String jvmmemmax = jvmmemmaxorig;
36     if (jvmmemmax != null && jvmmemmax.length() > 0)
37     {
38       long multiplier = 1;
39       switch (jvmmemmax.toLowerCase().substring(jvmmemmax.length() - 1))
40       {
41       case "t":
42         multiplier = 1099511627776L; // 2^40
43         jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
44         break;
45       case "g":
46         multiplier = 1073741824; // 2^30
47         jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
48         break;
49       case "m":
50         multiplier = 1048576; // 2^20
51         jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
52         break;
53       case "k":
54         multiplier = 1024; // 2^10
55         jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
56         break;
57       case "b":
58         multiplier = 1; // 2^0
59         jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
60         break;
61       default:
62         break;
63       }
64
65       // parse the arg
66       try
67       {
68         memmax = Long.parseLong(jvmmemmax);
69       } catch (NumberFormatException e)
70       {
71         memmax = maxHeapSizeDefault;
72         System.out.println("MemorySetting Property '" + maxHeapSizeProperty
73                 + "' ("
74                 + jvmmemmaxorig + "') badly formatted, using default ("
75                 + memmax + ").");
76       }
77
78       // apply multiplier if not too big (i.e. bigger than a long)
79       if (Long.MAX_VALUE / memmax < multiplier)
80       {
81         memmax = maxHeapSizeDefault;
82         System.out.println(
83                 "MemorySetting Property '" + maxHeapSizeProperty + "' ("
84                         + jvmmemmaxorig
85                         + ") too big, using default (" + memmax + ").");
86       }
87       else
88       {
89         memmax = multiplier * memmax;
90       }
91
92       // check at least minimum value (this accounts for negatives too)
93       if (memmax < MemorySetting.applicationMinMemory)
94       {
95         memmax = MemorySetting.applicationMinMemory;
96         System.out.println(
97                 "MemorySetting Property '" + maxHeapSizeProperty + "' ("
98                         + jvmmemmaxorig
99                         + ") too small, using minimum (" + memmax + ").");
100       }
101
102     }
103     else
104     {
105       // no need to warn if no setting
106       // System.out.println("MemorySetting Property '" + maxHeapSizeProperty + "' not
107       // set.");
108     }
109
110     // get max percent of physical memory
111     float percent = maxHeapSizePerCentDefault;
112     String jvmmempc = jvmmempcString;
113     if (jvmmempc == null)
114     {
115       jvmmempc = System.getProperty(maxHeapSizePerCentProperty);
116     }
117     long pcmem = -1;
118     try
119     {
120       if (jvmmempc != null)
121       {
122         float trypercent = Float.parseFloat(jvmmempc);
123         if (0 < trypercent && trypercent <= 100f)
124         {
125           percent = trypercent;
126         }
127         else
128         {
129           System.out.println(
130                   "MemorySetting Property '" + maxHeapSizePerCentProperty
131                   + "' should be in range 1..100");
132         }
133       }
134     } catch (NumberFormatException e)
135     {
136       System.out.println(
137               "MemorySetting property '" + maxHeapSizePerCentProperty
138                       + "' (" + jvmmempc + ") badly formatted");
139     }
140
141     // catch everything in case of no com.sun.management.OperatingSystemMXBean
142     boolean memoryPercentError = false;
143     try
144     {
145       pcmem = MemoryPercent.memPercent(percent);
146     } catch (Throwable t)
147     {
148       memoryPercentError = true;
149       System.out.println("Problem calling MemoryPercent.memPercent("
150               + percent
151               + "). Likely to be problem with com.sun.management.OperatingSystemMXBean");
152       t.printStackTrace();
153     }
154     // In the case of an error reading the percentage if physical memory, let's cap maxMemLong to 8GB
155     if (memoryPercentError && jvmmempc != null && pcmem == -1
156             && memmax > 8589934592L)
157     {
158       System.out.println(
159               "Capping maximum memory to 8GB due to failure to read physical memory size.");
160       memmax = 8589934592L;
161     }
162
163     if (pcmem == -1) // not set
164     {
165       maxMemLong = memmax;
166     }
167     else
168     {
169       maxMemLong = Math.min(pcmem, memmax);
170     }
171
172     return maxMemLong;
173   }
174
175 }