2012-11-24 42 views
10

假設我們有以下類:大多數JVM是否爲未使用的方法分配內存?

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:做未使用的靜態/實例方法佔據在運行時內存?那麼未使用的繼承或導入方法呢?

回答

12

未使用的方法仍然佔用內存作爲類/對象的一部分,即使它們沒有被直接調用。

如果它們被優化掉了,那麼這會使反射調用這些方法變得不可能。

有人可能會爭辯說,可能會產生一個優化,只會將方法存根存儲在內存中,並且垃圾會收集方法內容(如果有調用,則會從類文件中重新獲取該內容)。但是,我沒有意識到這樣做的虛擬機,並且由於內存中可能的最小增益和速度的折衷,當這種方法被調用時,將很難證明其合理性。

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

+0

你的意思是來自某些其他課程的反思性調用? – fny

+0

@faraz或者那個類本身 - 因爲反射方法調用根據定義在運行時決定,而不是編譯時間,所以編譯器無法知道什麼反射方法會被調用或何時調用。 – berry120

1

未使用的方法會增加類的大小,但類會存儲在所謂的PermGen內存中。存儲常規Java對象的堆內存不受類的大小影響

3

Abc的實例使用的內存不取決於Abc中有多少個方法。

當您添加方法時,生成的字節碼的大小顯然會增加,無論它們是否執行某些操作,但只會影響只加載一次的類對象Abc.class的大小,無論創建了多少實例。

2

由於類是在療法PermGen的薩法德對Sun熱點的JVM(會爲Java 8改變),你可以做這樣的事情,首先運行:

 

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); 
long before = memoryMXBean.getNonHeapMemoryUsage().getUsed(); 
new Dude(); // class must not be loaded before 
System.out.println("Usage of dude is " + (memoryMXBean.getNonHeapMemoryUsage().getUsed() - before) + " bytes"); 
 

你會看到這樣的事情: 哥們的用法是6432字節

然後創建一個哥們類沒有未使用的方法和運行測試:

 

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); 
long before = memoryMXBean.getNonHeapMemoryUsage().getUsed(); 
new DudeWithoutNeverDoThis(); // must not be loaded before 
System.out.println("Usage of dude without 'nerverDoThis' is " + (memoryMXBean.getNonHeapMemoryUsage().getUsed() - before) + " bytes"); 
 

,你看到的差別(用法哥們而不「nerverDoThis」是6176個字節

+0

在實際調用類的方法之後再次獲得數字,然後被稱爲1000次,這將會很有趣。調用該方法很多次會引起HotSpot將其編譯爲本地代碼,這會佔用內存。 –

0

的方法可以被編譯和加載到PerGen。

但JVM也許optimize方法使用method inlining

如:

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"); 
} 

所以,空方法永遠不會被調用。

相關問題