如何通过Java的Runtime api获取我的Java程序使用的内存? [英] How can I get the memory that my Java program uses via Java's Runtime api?

查看:152
本文介绍了如何通过Java的Runtime api获取我的Java程序使用的内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

There are similar questions out there, but they seem to avoid answering this specific question. How can I get the memory that my Java program uses via Java's Runtime api?

答案在哪里表明我可以做这样的事情:

The answer here indicates that I can do something like this:

System.out.println("KB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024);

但无论我运行哪个程序,这总是返回相同的数字。例如,下面我有一个程序,无论我在地图中放了多少个数字,内存使用量保持不变。

But this always returns the same number, no matter which program I run. For example, below I have a program where no matter how many numbers I put in the map, the memory usage stays the same.

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方法,输出为:

via cambecc's main method, output is:

推荐答案

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

You're doing it correctly. The way to get memory usage is exactly as you described:

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

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

But the reason your program always returns the same memory usage is because you are not creating enough objects to overcome the precision limitations of the freeMemory method. Although it has byte resolution, there is no guarantee for how precise freeMemory needs to be. The javadoc says as much:


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

an approximation to the total amount of memory currently available for future allocated objects, measured in bytes.

尝试以下操作,创建两个百万 NewObject 实例,并在每次 freeMemory 的结果更改时打印出来:

Try the following, which creates two million NewObject instances, and prints out each time the result of freeMemory changes:

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

在我的机器上,我看到如下输出

On my machine, I see output like the following

#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(尽管如果你运行实验,你将会看到这个数字有所不同。)

Notice how the reported free memory did not change until the 21,437th object was instantiated? The numbers suggest freeMemory for the JVM I'm using (Java7 Win 64-bit) has a precision of just over 2.5MB (although if you run the experiment, you'll see this number varies).

此代码与上述相同,但打印有关内存使用的更多细节。希望JVM的内存使用情况更清晰一些。我们在循环中不断分配新对象。在每次迭代期间,如果 totalMemory freeMemory 与上次迭代相同,我们不会打印任何内容。但如果其中一个发生了变化,我们会报告当前的内存使Δ值表示当前使用量与之前的内存报告之间的差异。

This code is the same as above, but prints more details about memory usage. Hopefully it's a bit clearer how the JVM's memory usage behaves. We continuously allocate new objects in a loop. During each iteration, if the totalMemory or freeMemory is the same as the last iteration, we don't print anything. But if either has changed, we report current memory usage. The values represent the difference between current usage and the previous memory report.

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实施等而有所不同:

On my notebook, I see the following output. Note your results will differ depending on OS, hardware, JVM implementation, etc.:

#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
...

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

There are a few observations from this data:


  1. 二手记忆倾向于包含如预期的那样。使用的内存包括活动对象和垃圾。

  2. 但在GC期间使用的内存减少,因为垃圾已被丢弃。例如,这发生在#419680。

  3. 可用内存量以块为单位减少,而不是逐字节减少。块大小不一。有时块很小,比如32字节,但通常它们更大,比如400K或800K。所以看起来块的大小会有所不同。但与总堆大小相比,变化看起来很小。例如,在#419681,块大小仅占总堆大小的0.6%。

  4. 正如预期的那样,可用内存趋于减少,直到GC启动并清除垃圾。发生这种情况时,可用内存会大幅增加,具体取决于丢弃的垃圾量。

  5. 此测试会产生大量垃圾。随着hashmap的大小增加,它会重新散列其内容,从而产生大量垃圾。

  1. Used memory tends to increase, as expected. Used memory includes live objects and garbage.
  2. But used memory decreases during a GC, because garbage has been discarded. For example, this occurred at #419680.
  3. The amount of free memory reduces in chunks, not byte-by-byte. The chunks vary in size. Sometimes the chunks are really tiny, like 32 bytes, but usually they are larger, like 400K, or 800K. So it appears the chunk size will vary a fair bit. But compared to total heap size, the variation appears tiny. For example, at #419681 the chunk size is only 0.6% of the total heap size.
  4. Free memory tends to decrease, as expected, until a GC kicks in and cleans up garbage. When this occurs, free memory increases pretty dramatically, depending on the amount of discarded garbage.
  5. This test generates a lot of garbage. As the hashmap grows in size, it rehashes its contents, thus generating a lot of garbage.

这篇关于如何通过Java的Runtime api获取我的Java程序使用的内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆