如何通过Java的Runtime api获取我的Java程序使用的内存?

时间:2013-06-28 22:44:29

标签: java api memory runtime

有类似的问题,但他们似乎避免回答这个具体问题。如何通过Java的Runtime api获取我的Java程序使用的内存?

答案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的main方法,输出为:

3085,总计:128516096,免费:127173744,点差:671120

173579,总计:128516096,免费:110033976,点差:671128

335207,总数:128516096,免费:92417792,差异:637544

672788,总数:224198656,免费:159302960,点差数:1221520

1171480,总数:224198656,免费版:106939136,Diff:1221544

1489771,总数:368377856,免费:227374816,点差:1212984

1998743,总数:368377856,免费版:182494408,差价:1212984

5 个答案:

答案 0 :(得分:49)

你正确地做到了。获取内存的方法完全如您所述:

Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()

但是程序总是返回相同内存使用量的原因是因为您没有创建足够的对象来克服freeMemory方法的精度限制。虽然它具有字节分辨率,但无法保证精确 freeMemory需要如何。 javadoc说了很多:

  

当前可用于未来分配对象的内存总量的近似值,以字节为单位。

尝试以下操作,创建两个百万 NewObject个实例,并在每次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的内存使用情况更清晰一些。我们不断在循环中分配新对象。在每次迭代期间,如果totalMemoryfreeMemory与上次迭代相同,我们不会打印任何内容。但如果有任何变化,我们会报告当前的内存使用情况。 值表示当前使用情况与之前的内存报告之间的差异。

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());
    }
}

在我的笔记本上,我看到以下输出。请注意,您的结果将根据操作系统,硬件,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
...

这些数据有一些观察结果:

  1. 正如预期的那样,使用的内存趋于增加。使用的内存包括活动对象和垃圾。
  2. 但在GC期间使用的内存减少,因为垃圾已被丢弃。例如,这发生在#419680。
  3. 可用内存量以块为单位减少,而不是逐字节减少。块大小不一。有时块很小,比如32字节,但通常它们更大,如400K或800K。所以看起来块大小会有一点变化。但与总堆大小相比,变化看起来很小。例如,在#419681,块大小仅为总堆大小的0.6%。
  4. 正如预期的那样,可用内存往往会减少,直到GC启动并清除垃圾。发生这种情况时,可用内存会显着增加,具体取决于丢弃的垃圾量。
  5. 此测试会产生大量垃圾。随着散列图的大小增加,它会重新散列其内容,从而产生大量垃圾。

答案 1 :(得分:3)

我有以下方法

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) + "%";
    }

以(以字节为单位)返回(使用过的)内存。

如果你想重新计算到MiB我有:

copy/paste image0 Sheets("Ficha_AMV").Select Range("c3").Select Selection.Copy ws.Select Range("c3").Select 'ActiveSheet.Paste ActiveSheet.PasteSpecial Format:="Picture (JPEG)", Link:=False, _ DisplayAsIcon:=False

答案 2 :(得分:1)

public static void memoryStats() {
    int mb = 1024 * 1024;
    // get Runtime instance
    Runtime instance = Runtime.getRuntime();
    System.out.println("***** Heap utilization statistics [MB] *****\n");
    // available memory
    System.out.println("Total Memory: " + instance.totalMemory() / mb);
    // free memory
    System.out.println("Free Memory: " + instance.freeMemory() / mb);
    // used memory
    System.out.println("Used Memory: "
            + (instance.totalMemory() - instance.freeMemory()) / mb);
    // Maximum available memory
    System.out.println("Max Memory: " + instance.maxMemory() / mb);
}

REF:Here

答案 3 :(得分:0)

以下可在您的java方法中使用以获取与内存相关的统计信息。

// Get the Java runtime
Runtime runtime = Runtime.getRuntime();
// Run the garbage collector
runtime.gc();
// Calculate the used memory
long memory = runtime.totalMemory() - runtime.freeMemory();
System.out.println("Used memory is bytes: " + memory);
System.out.println("Used memory is megabytes: "
+ bytesToMegabytes(memory));

答案 4 :(得分:0)

公平的空闲内存:

maxMemory() - totalMemory() + freeMemory()

和它一样:

maxMemory() - (used memory), where (used memory) = totalMemory() - freeMemory()

因为 freeMemory() 只为您提供 totalMemory() 内的可用内存,但 totalMemory() 仍然可以增长到 maxMemory()