#java #переменные #const #константа #pool
Не раз слышал о так называемом пуле констант в языке программирования Java. Знаю о пуле объектов типа String, пуле для типов Byte, Short, Character, Integer, Long и даже Boolean. Также знаю, что мы сами можем определять размер пула типа Integer, если запускать приложение с параметром -Djava.lang.Integer.IntegerCache.high=XX, где XX может колебаться в диапазоне от 127 до (Integer.MAX_VALUE - 129). Весь этот пул представляет собой массив, каждое значение которого является элементом расположенным в порядке числового возрастания и мы можем напрямую обратиться к нему по индексу за константное время O(1). Я прекрасно понимаю, где хранится этот массив. У каждого целочисленного обёрточного типа есть свой вложенный класс такого типа: private static class WrappingСlassNameCache {...} Где вместо WrappingСlassNameCache, мы подставляем конкретное имя класса, к примеру, IntegerCache. Внутри это выглядит так: private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } Ну Бог с ним, тут ничего мудрёного нет! А что же такое пул констант? Что он из себя представляет? И вообще где хранятся все константы в Java? Если мы говорим о локальных финализированных переменных, то они хранятся в стековой памяти. Если мы имеем дело со static final полями, то эти поля хранятся в MetaSpace (раньше в PermGen), если мы говорим о реализации JVM HotSpot. Так о каком вообще пуле может идти речь? Как всё это реализовано? Описано в каком-то классе, который поставляется вместе со стандартным API от Oracle (раньше Sun Microsystems) или же это нужно заглядывать в реализацию конкретной JVM и читать JVMS? Подскажите, пожалуйста, надоело, что в которой раз сталкиваюсь с этим понятием и никак не могу понять о чём идёт речь. Всем огромное спасибо за помощь! :)
Ответы
Ответ 1
У каждого класса свой пул констант. Чтобы понять для чего он нужен, разберём простой пример class Example { public void hello() { System.out.println("Hello"); } } Скомпилируем $ javac Example.java И заглянем внутрь $ javap -c -v Example.class public class Example minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#14 // java/lang/Object."":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #17 // Hello #4 = Methodref #18.#19 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #20 // Example #6 = Class #21 // java/lang/Object #7 = Utf8 #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 hello #12 = Utf8 SourceFile #13 = Utf8 Example.java #14 = NameAndType #7:#8 // " ":()V #15 = Class #22 // java/lang/System #16 = NameAndType #23:#24 // out:Ljava/io/PrintStream; #17 = Utf8 Hello #18 = Class #25 // java/io/PrintStream #19 = NameAndType #26:#27 // println:(Ljava/lang/String;)V #20 = Utf8 Example #21 = Utf8 java/lang/Object #22 = Utf8 java/lang/System #23 = Utf8 out #24 = Utf8 Ljava/io/PrintStream; #25 = Utf8 java/io/PrintStream #26 = Utf8 println #27 = Utf8 (Ljava/lang/String;)V { public Example(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object." ":()V 4: return LineNumberTable: line 1: 0 public void hello(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 3: 0 line 4: 8 } Первое, что представляет интерес - это байткоды метода hello: 0: getstatic #2 3: ldc #3 5: invokevirtual #4 Цифры до двоеточия обозначают байт, с которого начинается байткод и его параметры. По шагу видно, что каждая операция - это два байта, один байт на код операции и один байт на параметр. Байткоды могут принимать только параметры фиксированного размера - integer, long, short, byte, character, float, double, reference. Чтобы передать в метод println строку "Hello", надо загрузить в стек ссылку на строку "Hello", а саму строку где-то сохранить. Вот это где-то как раз и есть пул констант. А символы #3 после байткода ldc - ссылка на 3-й элемент в пуле констант. Constant pool: #1 = Methodref #6.#14 // java/lang/Object." ":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #17 // Hello #4 = Methodref #18.#19 // java/io/PrintStream.println:(Ljava/lang/String;)V Как можно увидеть из этого кусочка пула, его элементы сами часто ссылаются в пул. В частности наша строка под номером 3 ссылается на массив символов под номером 17. Если говорить о расположении пула констант в памяти JVM, то это один из участков MetaSpace.
Комментариев нет:
Отправить комментарий