当前位置: 首页 > 面试题库 >

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

穆才良
2023-03-14
问题内容

那里也有类似的问题,但是它们似乎避免回答这个特定问题。如何通过Java的Runtime API 获取 Java程序 使用的内存?

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

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

173579,总计:128516096,免费:110033976,区别:671128

335207,合计:128516096,免费:92417792,区别:637544

672788,总计:224198656,免费:159302960,差异:1221520

1171480,合计:224198656,免费:106939136,区别:1221544

1489771,总数:368377856,免费:227374816,区别:1212984

1998743,总数:368377856,免费:182494408,区别:1212984


问题答案:

您做对了。获取内存使用情况的方法与您所描述的完全相同:

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

但是,程序始终返回相同的内存使用量的原因是因为您没有创建足够的对象来克服该freeMemory方法的精度限制。尽管它具有字节 分辨率
,但不能保证需要达到的 精度 freeMemory。javadoc说了很多:

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

请尝试以下操作,这将创建200 万个 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个对象之前,报告的可用内存如何保持不变?这些数字表明freeMemory我正在使用的JVM(Java7 Win
64位)的精度刚好超过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. 此测试会产生大量垃圾。随着哈希图大小的增加,它会重新哈希其内容,从而产生大量垃圾。


 类似资料:
  • 我必须使用apache Nutch设计一个基于Java/Java EE的搜索引擎。我在互联网上搜索了很多关于apache nutch安装的文章,但找不到任何关于java程序访问或控制apache nutch进行爬行的文章/教程。

  • 问题内容: 我想在一个Java进程中运行多个REST Web应用程序,以节省内存并借助Akka轻松扩展。我想估计每个请求处理程序消耗多少内存,并检测整个系统的危险情况。 是否有可能几乎实时监视该进程中的内存使用情况,并找出每个请求处理程序使用了多少内存?我需要实现什么?有什么工具吗? 是否有可能捕获并根据内存使用量执行某些操作,例如仅崩溃超过请求的内存限制的请求处理程序?如果是这样,那有什么不好呢

  • 问题内容: 我需要检查是否可以显式设置可以传递给JVM的某些选项,或者是否具有其默认值。 更具体地说:我需要创建一个本机堆栈大小比默认线程大的特定线程,但是如果用户想通过指定-Xss选项自己处理此类事情,我想创建所有具有默认堆栈大小的线程(将由用户在-Xss选项中指定)。 我已经检查了类和,但是这些类并没有给我有关VM参数的任何有用信息。 有什么方法可以获取我需要的信息吗? 问题答案: 通过此代码

  • 假设我使用以下代码段通过java调用命令行程序 在这种情况下,将为exec调用的程序分配多少内存?它是否与分配给jvm的内存有关?如果是,我如何克服这个限制? UPDATE 根据这个问题给出的答案,如何解决"java.io.IOException: error=12, Cannot分配内存"调用Runtime#exec()? 运行时。getRuntime()。exec使用与main相同的内存量分配

  • 我正在创建我的图像的一个实例,比如 webmodule的Dockerfile公开了一个端口(例如8080)。 我现在的目标是获得映射/分配的端口号,该端口号可以通过Java从外部访问。有没有环境变量之类的? 用例:webmodule xy应该在另一个web应用程序上注册自己,并提供其IP端口,以便其他应用程序稍后可以联系webmodule xy。IP没有问题,但端口是。 我已经在GitHub上发现

  • 问题内容: 如何获得指向Java ByteBuffer内部数组的指针? PS:我这样做是为了共享Java和C ++使用的内存。 问题答案: ByteBuffer必须是直接起作用的字节缓冲区。