Java:为什么即使在创建对象之后JVM堆大小也没有区别

时间:2012-06-14 15:18:40

标签: java

我试图找出JVM堆大小与对象创建的不同之处。

例如,如果您看到我的下面的程序,我在for循环中创建了10000个String对象,但是我的JVM环境中的堆大小仍然没有差异。

public class One {

    public static void main(String args[]) {

        long heapSizebefore = Runtime.getRuntime().totalMemory();
        System.out.println("heapSizebefore" + heapSizebefore);

        for (int i = 0; i <= 10000; i++) {
            String str = new String();

        }

        long heapSizeafter = Runtime.getRuntime().totalMemory();
        System.out.println("heapSizeafter" + heapSizeafter);

    }

}

4 个答案:

答案 0 :(得分:4)

totalMemory的调用只会为您提供Java进程保留的内存量。这并不意味着它正在被堆上的对象主动填充。正如javadocs所说,它是当前和未来对象的可用内存总量

事实上,Java更愿意从底层操作系统请求大块内存,而不是每次创建新对象时都必须调用malloc(或等效)。

如果要跟踪堆的实际大小,可以使用JConsole / JVisualVM等工具实时完成此操作,或者使用内存分析器更详细地实现。如果您想以编程方式执行此操作,则需要为复杂内容注册代理,但堆详细信息通过JMX公开。查看java.lang:Memory MBean的HeapMemoryUsage属性(JConsole用于显示内存图表的属性)。

答案 1 :(得分:2)

JIT也可能优化整个for循环,因为它没有副作用。

答案 2 :(得分:2)

有两个原因:

  1. 您正在测量堆的保留内存量,而不是活动对象大小的总和。
  2. 您无论如何都不会保留对已分配字符串的引用,因此JVM可以随时对它们进行垃圾回收。

答案 3 :(得分:0)

  

基本上我想知道为什么我们在Java中使用静态方法。

因为静态方法比实例方法简单。

  

所以我的问题是保存内存(来自对象创建)我们使用静态方法??

没有。你应该有目的地编码,只创造你真正需要的东西。您可以在需要时创建实例,而在不需要时不创建实例。这不是出于性能原因,而是为了减少代码的概念性重量。如果你必须维护你的代码或一些elses代码,你需要找到为什么要做的事情,并且需要更长的时间来确定无意义的代码真的没有意义。即,寻找不存在的东西需要更长的时间,而不是那些东西。


为了支持多线程内存分配,每个线程都有一个线程本地分配缓冲区或TLAB

可用空间只显示公共池中有多少空闲空间,但是每个线程的TLAB中没有可用的空间。如果你分配了足够的字符串,当你加载另一个块时,你会看到内存使用量的突然跳跃。

您可以使用-XX:-UseTLAB

关闭此功能
// -XX:+UseTLAB heapUsedBefore: 5,368,848 heapUsedAfter: 5,368,848
// -XX:-UseTLAB heapUsedBefore: 535,048 heapUsedAfter: 535,096

public class One {
    public static void main(String... args) {
        Runtime runtime = Runtime.getRuntime();
        long heapUsedBefore = runtime.totalMemory() - runtime.freeMemory();

        String str = new String();

        long heapUsedAfter = runtime.totalMemory() - runtime.freeMemory();
        System.out.printf("heapUsedBefore: %,d heapUsedAfter: %,d%n", 
                           heapUsedBefore, heapUsedAfter);
    }
}