您做对了。获取内存使用情况的方法与您所描述的完全相同:
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的内存使用情况。我们不断循环分配新对象。在每次迭代中,如果
totalMemory或
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) { 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...
从这些数据中有一些观察结果:
- 如预期的那样,使用的内存趋于增加。已用内存包括活动对象和垃圾。
- 但是在GC期间,已用内存 减少 了,因为垃圾已被丢弃。例如,这发生在#419680。
- 可用内存量按块减少,而不是逐字节减少。块的大小各不相同。有时,块实际上很小,例如32个字节,但通常它们更大,例如400K或800K。因此,看起来块的大小会有所不同。但是与总堆大小相比,变化似乎很小。例如,在#419681处,块大小仅为堆总大小的0.6%。
- 像预期的那样,可用内存倾向于减少,直到GC启动并清理垃圾为止。发生这种情况时,根据废弃垃圾的数量,可用内存会急剧增加。
- 此测试会产生大量垃圾。随着哈希图大小的增加,它会重新哈希其内容,从而产生大量垃圾。



