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

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

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,区别: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. 此测试会产生大量垃圾。随着哈希图大小的增加,它会重新哈希其内容,从而产生大量垃圾。

以上是 如何通过Java的Runtime API获取Java程序使用的内存? 的全部内容, 来源链接: utcz.com/qa/414494.html

回到顶部