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

查看:60
本文介绍了如何通过 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 的内存使用行为更清晰一些.我们在循环中不断分配新对象.在每次迭代期间,如果 totalMemoryfreeMemory 与上次迭代相同,我们就不会打印任何内容.但是如果其中任何一个发生了变化,我们就会报告当前的内存使用情况. 值表示当前使用情况与之前的内存报告之间的差异.

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. 这个测试产生了很多垃圾.随着哈希图的大小增加,它会重新哈希其内容,从而产生大量垃圾.
  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天全站免登陆