大多数JVM是否为未使用的方法分配内存?

10

假设我们有以下的类:

class DoubleOhSeven {
  public static void doSomethingClassy();
  public static void neverDoThisClassy();
}

class Dude {
  public void doSomething();
  public void neverDoThis();
}

public class Party {
  public static void main(String[] args){
    DoubleOhSeven.doSomething();
    Dude guy = new Dude;
    guy.doSomething();
  }
}

当然,所有的方法都会被编译成它们对应的.class文件:未使用的静态/实例方法在运行时占用内存吗?未使用的继承或导入方法呢?

5个回答

12

未使用的方法仍作为类/对象的一部分占用内存,即使它们没有被直接调用。

如果对它们进行优化,那么就无法在这些方法上进行反射调用。

有人可能会认为可以生成一种优化,只在内存中存储方法存根,并回收方法内容(如果调用则从类文件重新获取)。但是,我不知道是否有一种虚拟机可以实现这一点,并且由于每次调用这样的方法时都需要权衡速度和内存中的最小利益,因此很难证明其合理性。

未使用的继承方法完全相同。


你的意思是从其他类中进行反射调用吗? - fny
@faraz 或者那个类本身 - 因为反射方法调用是在运行时而不是编译时决定的,所以编译器无法知道什么时候会调用反射方法或者调用哪些反射方法。 - Michael Berry

3

一个类的实例Abc所用的内存并不取决于Abc中有多少个方法。

当你添加方法时,生成的字节码显然会增加大小,无论这些方法是否有实际作用,但这只会影响类对象Abc.class的大小,该对象只加载一次,无论创建多少实例。


2
由于类在Sun Hotspot JVMs的PermGen中被保留(这将改变Java 8),您可以像这样操作,首先运行:

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
long before = memoryMXBean.getNonHeapMemoryUsage().getUsed();
new Dude(); // 类必须在之前没有被加载过
System.out.println("dude的使用情况为" + (memoryMXBean.getNonHeapMemoryUsage().getUsed() - before) + " 字节");

然后你会看到这样的结果:dude的使用情况为6432字节 然后创建一个不带未使用方法的Dude类并运行测试:

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
long before = memoryMXBean.getNonHeapMemoryUsage().getUsed();
new DudeWithoutNeverDoThis(); // 在此之前不能加载
System.out.println("不包含'nerverDoThis'的dude的使用情况为" + (memoryMXBean.getNonHeapMemoryUsage().getUsed() - before) + " 字节");

你会看到差异 (不包含'nerverDoThis'的dude的使用情况为6176字节)

在类上调用方法并且重复调用1000次后,重新获取数据将会很有趣。多次调用该方法将引发HotSpot编译成本地代码,这将占用内存。 - Tom Anderson

1

未使用的方法会增加类的大小,但类存储在所谓的PermGen内存中。堆内存,即存储常规Java对象的内存,不受类大小的影响。


0

该方法可以被编译并加载到PerGen。

但是JVM可能会使用方法内联来优化方法。

例如:

public class Test {

    public void foo(){
        System.out.println("foo");
        bar();
    }

    public void bar(){
        System.out.println("bar");
    }
}

该方法将由JIT编译器编译成以下形式:

public void foo(){
    System.out.println("foo");
    System.out.println("bar");
}

所以,空方法永远不会被调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接