Как отражение влияет на размер Перми? - PullRequest
9 голосов
/ 01 декабря 2009

Я понимаю, что размер perm используется для хранения метаданных, которые включают в себя байт-код, статические данные и т. Д.

Мой вопрос, как использование отражения влияет на размер завивки, если это когда-либо происходит. Я имею в виду, если Программа-А использует нормальный способ запуска объектов, а Программа-Б использует отражение во всем, как будут сравниваться размеры перми обеих программ

Ответы [ 4 ]

7 голосов
/ 01 декабря 2009

Пропускное пространство будет увеличиваться при выполнении кода, который будет загружать новые классы или интернализировать строки . Классы отражения должны быть загружены, это точно. Я не уверен, что API отражения действительно использует интернализованные строки, но это не должно быть трудно выяснить.

Например, для метода getDeclaredMethod(String name, Class<?>... parameterTypes) параметр имени будет интернализован.

Этот фрагмент хорошо заполнит область перми:

Random random = new Random();
while(true){
    try {
        X.class.getDeclaredMethod(toBinaryString(random.nextLong()));
    } catch (Exception e) {
    }
}

альтернативный текст http://img4.imageshack.us/img4/9725/permgen.jpg

В реальных приложениях это не имеет значения.

3 голосов
/ 01 декабря 2009

Отражение может генерировать классы, в зависимости от реализации. Например, вам может понадобиться использовать артефакт отражения тысячи раз, прежде чем он будет скомпилирован в байт-код.

Как всегда, совет: профилируйте свой код в реальных ситуациях.

3 голосов
/ 01 декабря 2009

Я не совсем уверен, что понимаю вопрос, но классы Java уже включают в себя все необходимое для их отражения. Файл .class не изменяется в зависимости от того, как он используется.

Редактировать 1: Предоставить несколько более конкретных примеров, чтобы лучше различать тип "отражения", о котором мы говорим.

Пример:

class Foo {
    public void bar() {
        System.out.println( "Hello, world." );
    }
}

// Conventional calling
Foo f = new Foo();
foo.bar();

// Reflection based callling
Class fooClass = Class.forName( "Foo" );
Method m = fooClass.getMethod( "bar", null );
Object f = fooClass.newInstance();
m.invoke( m, null );     

В обычном случае вызова будет загружен Foo.class и любые его прямые зависимости класса. планка будет выполнена. Строки «Foo» и «bar» уже будут интернированы как часть вызывающего класса, потому что байт-код использует строки для разрешения классов и методов во время выполнения. (фактически "bar" будет полной сигнатурой метода, поэтому на самом деле дольше, чем просто "bar")

В случае отражения происходит точно то же самое. Единственный дополнительный загруженный класс - это Method.class. Это должно быть единственное влияние на размер перми.

Последний случай влияет на производительность. Поиск метода является относительно дорогим, поэтому рекомендуется кэшировать объекты метода, когда это возможно. Дополнительный вызов метода для вызова имеет небольшое влияние на производительность, так как это дополнительный вызов метода. Hotspot будет иметь проблемы с оптимизацией через этот вызов ... по крайней мере, больше, чем обычно. JITing происходит точно так же.

Редактировать 2: Отметить некоторые дополнительные объекты, которые загружаются во время отражения ...

java.lang.Class будет создавать и кэшировать объекты метода (или объекты поля и т. Д.) При доступе. Они кэшируются в SoftReference и будут возвращены, если этого потребует использование памяти.

Однако инициализация этих объектов означает, что могут быть дополнительные интернированные строки, загруженные ВМ для поддержки создания этих объектов метода. Я предполагаю, что эти строки, вероятно, уже были частью пула констант отражающего класса, но возможно, что это не так. В любом случае, это одноразовое попадание на метод для каждого класса, для каждого поля для класса и т. Д. Получив доступ к методам, вы получите по крайней мере все имена для этих методов, которые были интернированы. Получив доступ к полям, вы получите имена этих полей, которые были интернированы.

2 голосов
/ 01 декабря 2009

Первый ответ в основном правильный - неважно, загружен ли класс «нормально» или с помощью рефлексии. В любом случае это загружено. Я не могу думать о какой-либо разнице в интернированных струнах, о которых я знаю.

Я полагаю, что есть более косвенный эффект: используя отражение, вы можете заставить загружаться меньше классов. Допустим, у вас есть некоторый код, который загружает один из 100 классов на основе некоторого параметра. Написав это без раздумий, вы импортируете все 100 классов и создадите один из них.

С отражением будет загружен только 1 класс. Без этого, в то время, когда класс с этим кодом загружается, все 100 импортированных классов будут загружаться, так как на них есть ссылки. Итак, больше классов загружается в область перми.

Но это несколько надуманный пример. Если это действительно не описывает вашу ситуацию, я думаю, вы не заметите практически никакой разницы. То есть, пока вы не уверены, что это не тривиально, не позволяйте этому влиять на ваши дизайнерские решения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...