Вы часто можете увидеть дискуссии по распределению памяти струн Java при запуске в основных разделах в Интернете, таких как: String a = "123", строка B = новая строка ("123"), где эти две формы строк хранятся? Фактически, буквальное значение строки «123» в этих двух формах не хранится ни на стеке, ни в куче во время выполнения. Они хранятся в определенной постоянной области в области метода, и только одна копия сохраняется в памяти для того же строкового буквального значения. Мы проанализируем это с примерами ниже.
1. Оператор == используется в двух случаях, когда сравниваются два сравнения ссылки строки:
открытый класс StringTest {public static void main (string [] args) {// Часть 1 String S1 = "I Love China"; Строка S2 = "Я люблю Китай"; System.out.println ("Результат:" + s1 == s2); // Результат программы запуска является истинной // Часть 2 строка s3 = new String ("I Love China"); String S4 = новая строка («Я люблю Китай»); System.out.println ("result:" + s3 == s4); // Результат программы запуска false}}}}Мы знаем, что оператор == в Java сравнивает значения переменных. Значение переменной, соответствующей типу ссылки, хранит адрес справочного объекта. Здесь строка - это ссылочный тип, и значения четырех переменных здесь фактически хранят адреса строки. Результат выполнения для Part2 очевиден, потому что новый оператор приведет к тому, что JVM создает новые объекты в куче во время выполнения, а адреса двух разных объектов различны. Однако из результата выполнения части 1 можно увидеть, что S1 и S2 являются одним и тем же адресом. Так, на что хранятся в строках переменными S1 и S2? Как JVM обрабатывает строки? Точно так же, для разных строковых объектов в куче, на которые указывает переменные S3 и S4, они сохранят строку «Я люблю Китай» в своем собственном пространстве объекта? Чтобы понять, как JVM обрабатывает струны, сначала мы смотрим на инструкции по байт -коду, сгенерированные компилятором Java. Благодаря инструкции ByteCode мы анализируем, какие операции будут выполнены JVM.
2. Ниже приведена некоторая информация о байт -коде, сгенерированную программой. Красные отмечают ту часть, на которую нам нужно обратить внимание.
Постоянный пул: #1 = класс #2 // StringTest #2 = UTF8 StringTest #3 = Класс № 4 // Java/Lang/Object #4 = UTF8 Java/Lang/Object #5 = UTF8 <Int> #6 = UTF8 () V #7 = UTF8 CODE #8 = MethodRef #3. #9 // Java/lang/object. Nameandtype #5: #6 // "<int>" :() v #10 = utf8 LineNumberTable #11 = UTF8 LocalVariabletable #12 = utf8 This #13 = UTF8 LStringTest; #14 = utf8 Main #15 = UTF8 ([ljava/lang/string;) V #16 = String #17 // Я люблю ссылку на Китай на строки адрес #17 = utf8 Я люблю Китай #18 = Fieldref #19. #21 // java/lang/system.out: ljava/io/printStream; #19 = класс #20 // java/lang/system #20 = utf8 java/lang/system #21 = nameandtype #22: #23 // out: ljava/io/printStream; #22 = UTF8 OUT #23 = UTF8 LJAVA/IO/PRINTSTREAM; #24 = класс #25 // java/lang/stringbuilder #25 = utf8 java/lang/stringbuilder #26 = String #27 // Результат: #27 = utf8 Результат: #28 = MethodRef #24. #29 // Java/lang/StringBuilder. "<Itin>" :( ljava/lang/string; "<int>" :( ljava/lang/string;) v#30 = utf8 (ljava/lang/string;) v#31 = methodRef#24.#32 // java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder;#32 = nameandtype#33:#34/#34/ Приложение: (z) ljava/lang/stringbuilder;#33 = UTF8 Приложение#34 = UTF8 (z) ljava/lang/stringbuilder;#35 = methodRef#24.#36 // java/lang/stringbuilder.toString :() ljava/lang/string; ToString :() ljava/lang/string;#37 = UTF8 ToString#38 = utf8 () ljava/lang/string;#39 = methodRef#40.#42 // java/io/printstream.println: (ljava/lang/string;) v#40 = class#41 //ava/io####iom/####io UTF8 java/io/printStream#42 = nameandtype#43:#30 // println: (ljava/lang/string;) v#43 = utf8 println#44 = класс#45 // java/lang/string#45 = utf8 java/lang/string#46 = метод#44.#29 // 29 // 29//#29//#29//#29 // 29//#29//#29/#45 = utf8 java/lang/string#46 = methodRef#44. java/lang/string. "<init>" :( ljava/lang/string;) V#47 = UTF8 args#48 = utf8 [ljava/lang/string;#49 = UTF8 S1#50 = UTF8 ljava/lang/string;#51 = UTF8 S2#52 = UTF8 S3#53 = UTF8#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54#54# StackMaptable#55 = класс#48 // "[ljava/lang/string;"#56 = UTF8 SourceFile#57 = UTF8 stringTest.java ............ // Инструкция ByteCode для соответствующего метода объясняется и выполняется во время выполнения JVM. Public Static Void Main (java.lang.string []); Дескриптор: ([ljava/lang/string;) V Флаги: acc_public, acc_static Code: Stack = 4, локалы = 5, args_size = 1 0: ldc #16 // string I Love China, эта директива относится к символу в стеке #16 постоянного пула, и здесь подталкивает строку «Ilove China» на вершину стека. Эта инструкция соответствует следующей инструкции 2. String S1 = «Я люблю Китай». Эта инструкция и следующая инструкция 5 соответствуют утверждению строки S2 = «Я люблю Китай» в программе. 5: Store_2 // Назначить ссылки на объекты на локальные переменные в верхней части стека. 6: 6: GetStatic #18 // поле Java/Lang/System.out: Ljava/IO/PrintStream; 9: Новый #24 // класс Java/Lang/StringBuilder 12: DUP 13: LDC #26 // Результат строки: 15: INVOKPECIAL #28 // Метод Java/Lang/StringBuilder. "<Intice>" :( ljava/lang/string;) v 18: Aload_1 19: Aload_2 20: if_ACMP. Сравните, равны ли они или нет, перейдите к Директиве 27, выполните, выполните следующую инструкцию в равной степени 23: ICONST_1 24: GOTO 28 27: ICONST_0 28: Invokevirtual #31 // Метод Java/lang/StringBuilder.append: (z) ljava/lang/stringbuilder; 31: Invokevirtual #35 // Метод Java/lang/stringbuilder.tostring :() ljava/lang/string; 34: Invokevirtual #39 // Метод Java/io/printStream.println: (ljava/lang/string;) V 37: Новый #44 // класс Java/Lang/String, создайте объект, который расположен на вершине штабель. 40: DUP // Скопируйте копию объекта в верхней части стека и нажмите на верхнюю часть стека. 41: LDC #16 // Строка Я люблю Китай, так же, как 0, 3 инструкции. 43: Invokespecial #46 // Метод java/lang/string. "<int>" :( ljava/lang/string;) V 46: Store_3 47: новый #44 // класс Java/Lang/String // Создайте объект и подтолкните объект к верху 53: Invokespecial #46 // Метод Java/Lang/String. java/lang/system.out: ljava/io/printstream; 61: новый #24 // класс Java/Lang/StringBuilder 64: DUP 65: LDC #26 // Результат строки: 67: INVOKEPCIAL #28 // Метод Java/Lang/StringBuilder.append: (z) ljava/lang/stringbuilder; 84: InvokeVirtual #35 // Метод java/lang/stringbuilder.tostring :() ljava/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 84: InvokeVirtual #35 // Метод java/lang/stringbuilder.tostring :() ljava/lang/stringbuilder; 87: InvokeVirtual #39 // Метод Java/io/printStream.println: (ljava/lang/string;) v 90: return ......... LineNumberTable: Линия 7: 0line 8: 3line 9: 6line 11: 37line 12: 47line 13: 58line 14: 90localvariabletable: Start Linse. [Ljava/lang/string; // локальная переменная 088 1 s1 ljava/lang/string; // локальная переменная 185 2 S2 ljava/lang/string; // локальная переменная 244 3 s3 ljava/lang/string; // локальная переменная 333 4 s4 ljava/lang/string; // локальная переменная 4
Красная часть байт -кода связана с нашим обсуждением. Через сгенерированный байт -код мы можем сделать следующие выводы для примера программы.
1). Когда компилятор Java собирает программу в Bytecode, константа строки «я люблю Китай», впервые определяющая, существует ли она в постоянном бассейне Bytecode. Если его не существует, это не создаст его. То есть равная строка зарезервирована. Только одна копия может быть найдена с помощью символических ссылок, так что строковые переменные S1 и S2 в программе точели на одну и ту же константу строки в постоянном пуле. Во время выполнения JVM будет хранить константы строк в бассейне постоянного байт -кода в расположении области метода, обычно называемой постоянным пулом, а строка доступна через индексы в форме массива символов. JVM указывает на относительный эталонный адрес строки, указанный на S1 и S2 на фактический адрес памяти строки во время выполнения.
2). Для строки S3 = новая строка («Я люблю Китай»), строку S4 = новая строка («I Love China»), из Bytecode видно, что она вызывает новую инструкцию. JVM создаст два разных объекта во время выполнения, а S3 и S4 указывают на разные адреса объекта. Следовательно, результат сравнения S3 == S4 является ложным.
Во -вторых, для инициализации объектов S3 и S4 из байт -кода видно, что метод init объекта называется, а ссылка «Я люблю Китай» в постоянном пуле. Итак, каково создание строкового объекта и инициализации? Мы можем проверить исходный код строки и байт -код, сгенерированный объектом String, чтобы лучше понять, копируется ли строка внутри объекта, или ссылка непосредственно по адресу постоянного пула, соответствующего строке, указана.
3. Часть исходного кода объекта строки:
<Span style = "font-size: 14pt"> public final Class String реализует java.io.serializable, сопоставимый <string>, charequestence { /** Значение используется для хранения символов. */ Частное окончательное значение char []; / ** Кэш хэш -код для строки*/ private int hash; // по умолчанию 0 public String () {this.value = new char [0]; } </Span> <span style = "founal-color: #ffffff; font-size: 18pt"> public String (string Original) {this.value = Original.value; this.hash = Original.hash; } </Span>Из исходного кода мы видим, что в классе строки есть значение arbable arbable []. С помощью метода строительства мы видим, что объект не выполняет операции копирования при инициализации, а только назначает ссылку на адрес продленного строкового объекта значению переменной экземпляра. Исходя из этого, мы можем изначально сделать вывод, что даже когда строковый объект создается с использованием новой строки («ABC»), пространство выделяется для объекта в куче памяти, но никакая информация о самой «ABC» не хранится в куче, но ссылка на строку «ABC» инициатируется в его переменной экземпляра по строке «ABC». На самом деле, это также для того, чтобы сохранить пространство для хранения памяти и улучшить производительность программы.
4. Давайте посмотрим на информацию об объекте String String:
public java.lang.string (); Descriptor: () V Флаги: ACC_Public Code: Stack = 2, локалы = 1, args_size = 1 0: aload_0 1: invokespecial #1 // Метод java/lang/obj 138: 4 строка 139: 11 Public Java.Lang.String (Java.Lang.String); Дескриптор: (ljava/lang/string;) v Флаг: ACC_PUBLIC CODE: Stack = 2, локалы = 2, args_size = 2 0: aload_0 // Толкнуть локальную переменную 0 в верхнюю часть стека, ссылка на свой собственный объект. 1: Invokespecial #1 // Метод Java/Lang/Object. 4: aload_0 // Нажмите ссылку на свой собственный объект в верхнюю часть стека. 5: ALOAD_1 // Проданная ссылка на строку в верхнюю часть стека. 6: Getfield #2 // Значение поля: [C // вспять ссылку на строку в верхней части стека и назначьте ее переменной экземпляра на #2 и сохраните ее в стеке. 9: Putfield #2 // Значение поля: [C // вспять ссылку на строку в верхней части стека и самого объекта и присваивайте ссылку на строку на переменную экземпляра самого объекта. 12: aload_0 13: aload_1 14: getfield #3 // Полевой
С точки зрения Bytecode, мы можем сделать вывод, что New String («ABC») выполняет назначения ссылок на строки при построении нового объекта, а не копировал строки. Выше приведено анализ и краткое изложение распределения памяти строк с точки зрения исходного кода и байтового кода.
Приведенный выше анализ и краткое изложение распределения памяти Java (рекомендуется) - это все контент, которым я делюсь с вами. Я надеюсь, что вы можете дать вам ссылку, и я надеюсь, что вы сможете поддержать Wulin.com больше.