Большинство 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
: не используются ли неиспользуемые статические методы/экземпляры в памяти во время выполнения? Что относительно неиспользуемых унаследованных или импортированных методов?
Ответы
Ответ 1
Неиспользуемые методы по-прежнему занимают память как часть класса/объекта, даже если они не вызываются напрямую.
Если бы они были оптимизированы, то это сделало бы рефлексивные призывы к этим методам невозможным.
Можно утверждать, что может быть сгенерирована оптимизация, которая хранит только заглушку метода в памяти, а мусор собирает содержимое метода (которое затем было бы повторно отображено из файла класса, если был сделан вызов). Однако, m не знает о VM, которая делает это, и было бы трудно оправдать из-за вероятного минимального выигрыша в памяти и компромисса в скорости при вызове такого метода.
Неиспользуемые унаследованные методы будут точно такими же.
Ответ 2
Память, используемая экземпляром класса Abc
, не зависит от того, сколько методов существует в Abc
.
Сгенерированный байт-код, очевидно, увеличивает размер при добавлении методов, независимо от того, что они делают что-то или нет, но это повлияет только на размер объекта класса Abc.class
, который загружается только один раз, независимо от того, сколько экземпляров создан.
Ответ 3
Так как классы защищены в ПерминГен для JVM Sun Hotspot (это изменится для 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 байта.
И затем создайте класс Dude без неиспользуемого метода и запустите тест:
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 байт)
Ответ 4
Неиспользуемые методы увеличивают размер класса, но классы хранятся в так называемой памяти PermGen. Память кучи, где хранятся обычные объекты Java, не зависит от размера класса
Ответ 5
Метод может быть скомпилирован и загружен в 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");
}
Таким образом, пустой метод никогда не будет вызываться.