似たような質問がありますが、この特定の質問に答えるのを避けているようです。 my Java programがJavaのランタイムAPIを介して使用するメモリを取得するにはどうすればよいですか?
答え here は、私がこのようなことができることを示します:
System.out.println("KB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024);
ただし、どのプログラムを実行しても、これは常に同じ数を返します。たとえば、以下のプログラムでは、マップにいくつの数字を入れても、メモリ使用量は同じままです。
package memoryTest;
import Java.util.HashMap;
import Java.util.Map;
public class MemoryTest {
static Map<Integer, NewObject> map = new HashMap<Integer, NewObject>();
public static void main(String[] args){
System.out.println("KB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024);
fillMemory(25);
System.out.println("KB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024);
}
static int j=0;
public static void fillMemory(int i){
for(int k=0; k< 2000; k++)
map.put(j++, new NewObject());
}
public static class NewObject{
long i = 0L;
long j = 0L;
long k = 0L;
}
}
cambeccのメインメソッドを介した出力は次のとおりです。
あなたはそれを正しくやっています。メモリ使用量を取得する方法は、説明したとおりです。
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
しかし、プログラムが常に同じメモリ使用量を返すのは、freeMemory
メソッドの精度の制限を克服するのに十分なオブジェクトを作成していないためです。バイト解像度がありますが、精度freeMemory
の必要性については保証されていません。 javadocは次のように言っています:
将来割り当てられるオブジェクトに現在使用可能なメモリの総量の概算(バイト単位)。
次を試してください。2つのmillionNewObject
インスタンスが作成され、freeMemory
の結果が変わるたびに出力されます。
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
long prevTotal = 0;
long prevFree = rt.freeMemory();
for (int i = 0; i < 2_000_000; i++) {
long total = rt.totalMemory();
long free = rt.freeMemory();
if (total != prevTotal || free != prevFree) {
System.out.println(
String.format("#%s, Total: %s, Free: %s, Diff: %s",
i,
total,
free,
prevFree - free));
prevTotal = total;
prevFree = free;
}
map.put(i, new NewObject());
}
}
私のマシンでは、次のような出力が表示されます
#0, Total: 513998848, Free: 508635256, Diff: 0
#21437, Total: 513998848, Free: 505953496, Diff: 2681760
#48905, Total: 513998848, Free: 503271728, Diff: 2681768
#73394, Total: 513998848, Free: 500589960, Diff: 2681768
#103841, Total: 513998848, Free: 497908192, Diff: 2681768
...
21,437番目のオブジェクトがインスタンス化されるまで、報告された空きメモリがどのように変化しなかったかに注目してください。数値は、使用しているJVM(Java7 Win 64ビット)のfreeMemory
が2.5MBをわずかに超える精度を持っていることを示唆しています(ただし、実験を実行すると、この数値は異なります)。
このコードは上記と同じですが、メモリ使用量に関する詳細を出力します。 JVMのメモリ使用量の振る舞いが少し明確になっていることを願っています。ループ内で新しいオブジェクトを継続的に割り当てます。各反復中に、totalMemory
またはfreeMemory
が最後の反復と同じ場合、何も出力しません。ただし、どちらかが変更された場合、現在のメモリ使用量を報告します。 ∆
値は、現在の使用状況と以前のメモリレポートの違いを表します。
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
long prevTotal = 0;
long prevFree = rt.freeMemory();
for (int i = 0; i < 2_000_000; i++) {
long total = rt.totalMemory();
long free = rt.freeMemory();
if (total != prevTotal || free != prevFree) {
long used = total - free;
long prevUsed = (prevTotal - prevFree);
System.out.println(
"#" + i +
", Total: " + total +
", Used: " + used +
", ∆Used: " + (used - prevUsed) +
", Free: " + free +
", ∆Free: " + (free - prevFree));
prevTotal = total;
prevFree = free;
}
map.put(i, new NewObject());
}
}
私のノートブックには、次の出力が表示されます。 OS、ハードウェア、JVM実装などによって結果が異なることに注意してください。
#0, Total: 83427328, Used: 1741048, ∆Used: 83427328, Free: 81686280, ∆Free: 0
#3228, Total: 83427328, Used: 1741080, ∆Used: 32, Free: 81686248, ∆Free: -32
#3229, Total: 83427328, Used: 2176280, ∆Used: 435200, Free: 81251048, ∆Free: -435200
#7777, Total: 83427328, Used: 2176312, ∆Used: 32, Free: 81251016, ∆Free: -32
#7778, Total: 83427328, Used: 2611536, ∆Used: 435224, Free: 80815792, ∆Free: -435224
...
#415056, Total: 83427328, Used: 41517072, ∆Used: 407920, Free: 41910256, ∆Free: -407920
#419680, Total: 145358848, Used: 39477560, ∆Used: -2039512, Free: 105881288, ∆Free: 63971032
#419681, Total: 145358848, Used: 40283832, ∆Used: 806272, Free: 105075016, ∆Free: -806272
...
このデータからいくつかの観察があります:
私は次の方法を持っています
public static long getMaxMemory() {
return Runtime.getRuntime().maxMemory();
}
public static long getUsedMemory() {
return getMaxMemory() - getFreeMemory();
}
public static long getTotalMemory() {
return Runtime.getRuntime().totalMemory();
}
public static long getFreeMemory() {
return Runtime.getRuntime().freeMemory();
}
(使用済み)メモリをバイト単位で返します。
MiBに再計算する場合は、次のようにします。
private static final long MEGABYTE_FACTOR = 1024L * 1024L;
private static final DecimalFormat ROUNDED_DOUBLE_DECIMALFORMAT;
private static final String MIB = "MiB";
static {
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.ENGLISH);
otherSymbols.setDecimalSeparator('.');
otherSymbols.setGroupingSeparator(',');
ROUNDED_DOUBLE_DECIMALFORMAT = new DecimalFormat("####0.00", otherSymbols);
ROUNDED_DOUBLE_DECIMALFORMAT.setGroupingUsed(false);
}
public static String getTotalMemoryInMiB() {
double totalMiB = bytesToMiB(getTotalMemory());
return String.format("%s %s", ROUNDED_DOUBLE_DECIMALFORMAT.format(totalMiB), MIB);
}
public static String getFreeMemoryInMiB() {
double freeMiB = bytesToMiB(getFreeMemory());
return String.format("%s %s", ROUNDED_DOUBLE_DECIMALFORMAT.format(freeMiB), MIB);
}
public static String getUsedMemoryInMiB() {
double usedMiB = bytesToMiB(getUsedMemory());
return String.format("%s %s", ROUNDED_DOUBLE_DECIMALFORMAT.format(usedMiB), MIB);
}
public static String getMaxMemoryInMiB() {
double maxMiB = bytesToMiB(getMaxMemory());
return String.format("%s %s", ROUNDED_DOUBLE_DECIMALFORMAT.format(maxMiB), MIB);
}
public static double getPercentageUsed() {
return ((double) getUsedMemory() / getMaxMemory()) * 100;
}
public static String getPercentageUsedFormatted() {
double usedPercentage = getPercentageUsed();
return ROUNDED_DOUBLE_DECIMALFORMAT.format(usedPercentage) + "%";
}