Распределение и управление памятью Java являются одной из основных технологий Java. Ранее мы представили знание управления памятью Java, утечки памяти и коллекции мусора Java. Сегодня мы снова пойдем глубоко в ядро Java и подробно рассмотрим знание Java в распределении памяти. Как правило, Java будет включать следующие области при распределении памяти:
◆ Регистрация: мы не можем контролировать его в программе
◆ стек: хранит основные типы данных и ссылки на объекты, но сам объект не хранится в стеке, но хранится в куче (объект, который выходит из нового)
◆ Куча: храните данные, сгенерированные с использованием новых
◆ Статический домен: статические элементы, хранящиеся в объекте, определенном со статическим
◆ Постоянный бассейн: константы магазина
◆ Несоответствующее хранилище: постоянное место для хранения, такое как жесткий диск
Стек в распределении памяти Java
Некоторые основные типы данных переменных, определенные в функции, и эталонные переменные объекта, все выделены в памяти стека функции.
Когда переменная определяется в блоке кода, Java выделяет пространство памяти для переменной в стеке. Когда переменная выходит из области, Java автоматически отпустит пространство памяти, выделенное для переменной, и пространство памяти может использоваться отдельно немедленно. Размер данных и жизненный цикл в стеке определенные, и эти данные исчезают, когда не указывает на данные.
Куча в распределении памяти Java
Хиповая память используется для хранения объектов и массивов, созданных новыми. Память, выделяемая в куче, управляется автоматическим коллекционером мусора Java Virtual Machine.
После того, как массив или объект генерируется в куче, в стеке можно определить специальную переменную, так что значение этой переменной в стеке равно первое адреса массива или объекта в памяти кучи, а переменная в стеке становится эталонной переменной для массива или объекта. Справочная переменная эквивалентна имени, данному массиву или объекту. Вы можете использовать эталонные переменные в стеке в программе для доступа к массиву или объекту в куче. Справочная переменная эквивалентна имени, данному массиву или объекту.
Справочные переменные - это обычные переменные, которые присваиваются в стеке при определении. Справочные переменные выпускаются после того, как программа выходит за рамки его масштаба. Массив и объект сами выделяются в куче. Даже если программа работает за пределами блока кода, где расположены новые операторы для генерации массива или объекта, память, занятая массивом и самим объектом, не будет выпущена. Массив и объект становятся мусором только тогда, когда нет эталонной переменной, указывающей на него, и нельзя использовать, но все же займите пространство памяти. Он собирается (выпущено) коллекционером мусора в неопределенное время. Это также причина, по которой Java занимает больше памяти.
На самом деле, переменные в стеке указывают на переменные в памяти кучи, что является указателем в Java!
Куча и стек
Куча Java - это область данных среды выполнения, из которой объекты выделяют пространство. Эти объекты создаются с помощью таких инструкций, как новый, Newarray, Anewarray и Multianewarray. Они не требуют явного выпуска программного кода. Куча отвечает за сбор мусора. Преимущество кучи заключается в том, что она может динамически распределять размер памяти и не должен сообщать компилятору заранее, потому что он динамически распределяет память во время выполнения. Коллекционер мусора Java автоматически собирает данные, которые больше не используются. Но недостаток заключается в том, что, поскольку ему необходимо динамически распределять память во время выполнения, скорость доступа медленнее.
Преимущество стека состоит в том, что скорость доступа быстрее, чем куча, уступая только регистрам, а данные стека могут быть переданы. Но недостатком является то, что размер и срок службы данных в стеке должен быть детерминированным и отсутствовать гибкость. В стеке в основном хранится некоторые основные типы переменных данных (Int, короткие, длинные, байт, поплавок, двойной, логический, char) и объектные ручки (ссылки).
Очень важной особенностью стека является то, что данные, существующие в стеке, могут быть обмен. Предположим, мы определяем одновременно:
Код Java
int a = 3;
int b = 3;
Компилятор сначала обрабатывает int a = 3; Сначала он создаст ссылку в стеке с переменной A, а затем выясните, есть ли значение 3 в стеке. Если это не найдено, он будет хранить 3, а затем точку A до 3. Затем процесс int b = 3; После создания эталонной переменной B, поскольку в стеке уже есть значение 3, B напрямую указывает на 3. Таким образом, A и B оба указывают на 3 одновременно.
В настоящее время, если a = 4 снова установлен; Затем компилятор снова будет искать, есть ли 4 значения в стеке. Если нет, храните 4 и точку от A до 4; Если это уже существует, укажите A на этот адрес напрямую. Следовательно, изменение значения А не повлияет на значение b.
Следует отметить, что этот обмен данными отличается от обмена ссылками из двух объектов, указывающих на один объект одновременно, потому что в этом случае модификация A не повлияет на B, это осуществляется компилятором, что способствует сохранению пространства. Переменная ссылка объекта изменяет внутреннее состояние этого объекта и будет влиять на ссылку на другую ссылку объекта.
Код Java
1.int i1 = 9;
2.int i2 = 9;
3. int i3 = 9;
4. Публичный статический конечный int int1 = 9;
5. Публичный статический конечный int int2 = 9;
6. Публичный статический окончательный финал int3 = 9;
Для переменных членов и локальных переменных: переменные -члены - это переменные, определенные внутри метода и класса; Локальные переменные - это переменные, определенные внутри метода или блока операторов. Локальные переменные должны быть инициализированы.
Формальные параметры являются локальными переменными, а данные локальных переменных существуют в памяти стека. Локальные переменные в памяти стека исчезают, когда метод исчезает.
Переменные элемента хранятся в объектах в куче и собираются коллекционером мусора.
Как в следующем коде:
Код Java
классная дата рождения {частный день; частный месяц INT; частный год; публичная дата рождения (int d, int m, int y) {day = d; месяц = м; Год = у; } omit get, set method ……} public class test {public static void main (string args []) {int date = 9; Тест -тест = новый тест (); test.Change (дата); Дата рождения D1 = новая дата рождения (7,7,1970); } public void -изменение1 (int i) {i = 1234; }Для приведенного выше кода дата является локальной переменной, я, D, M, Y - это формальные параметры в качестве локальных переменных, а день, месяц и год являются переменными членами. Давайте проанализируем изменения во время выполнения кода:
1. Основной метод начинает выполнять: int date = 9;
Дата локальные переменные, основные типы, ссылки и значения присутствуют в стеке.
2. Тест -тест = новый тест ();
Тест является ссылкой на объект, он существует в стеке, а объект (новый тест ()) существует в куче.
3. test.Change (дата);
Я локальная переменная, а ссылка и значение присутствуют в стеке. Когда изменение метода будет выполнено, я исчезню из стека.
4. Дата рождения D1 = новая дата рождения (7,7,1970);
D1 является ссылкой на объект и существует в стеке. Объекты (новая дата рождения ()) существуют в куче, где d, m, y - локальные переменные, хранящиеся в стеке, а их типы являются базовыми типами, поэтому их данные также хранятся в стеке. День, месяц, год являются переменными членами, и они хранятся в куче (новая дата рождения ()). Когда конструктор даты рождения будет выполнен, D, M, Y исчезнет из стека.
5. После выполнения основного метода будет исчезнуть основной метод, исчезнет ссылка на дату, тест и D1, и New Test () New Birthdate () будет ждать сбора мусора.
Постоянный бассейн
Постоянные пулы относятся к некоторым данным, которые определяются в период компиляции и сохраняются в скомпилированном файле .class.
В дополнение к содержанию постоянных значений (конечных) различных основных типов (таких как Int, Long и т. Д.) и типов объектов (например, строки и массивы), определенные в коде, он также содержит некоторые символические ссылки в текстовой форме, такие как:
◆ Полностью квалифицированные названия классов и интерфейсов;
◆ Имя и дескриптор поля;
◆ Методы, имена и дескрипторы.
Если период компиляции был создан (определяется непосредственно в двойных кавычках), он будет храниться в постоянном пуле, и, если он может быть определен с периодом прогона (от нового), он будет храниться в куче. Для строк с равными всегда есть только одна копия в постоянном пуле и несколько копий в куче.
Строка - это специальные данные упаковки. Можно использовать:
Код Java
String str = new String ("abc"); string str = "abc";Есть две формы для создания. Первый - использовать новый () для создания нового объекта, который будет храниться в куче. Новый объект создается каждый раз, когда его называют. Второй тип состоит в том, чтобы сначала создать переменную STR для объекта класса строки в стеке, а затем использовать символическую ссылку, чтобы узнать, есть ли «ABC» в пуле постоянной строки. Если нет, храните «ABC» в бассейн Constant String и позвольте STR указать на «ABC». Если уже есть «ABC», тогда напрямую позвольте STR наметить на «ABC».
При сравнении, являются ли значения в классе равными, используйте метод equals (); При тестировании, указывают ли ссылки двух классов обертки на один и тот же объект, используйте == и используйте пример ниже, чтобы проиллюстрировать вышеуказанную теорию.
Код Java
String str1 = "abc"; string str2 = "abc"; system.out.println (str1 == str2); //истинный
Видно, что Str1 и STR2 указывают на тот же объект.
Код Java
String str1 = new String ("abc"); string str2 = new String ("abc"); System.out.println (str1 == str2); // ЛОЖЬНовый метод состоит в том, чтобы генерировать разные объекты. Генерируйте по одному за раз.
Следовательно, во втором пути создаются несколько строк «ABC», и в памяти есть только один объект. Этот метод написания полезен и сохраняет пространство памяти. В то же время он может в определенной степени улучшить скорость работы программы, поскольку JVM автоматически решает, необходимо ли создавать новый объект на основе фактической ситуации данных в стеке. Для кода строки str = new String ("ABC");, новые объекты создаются в куче независимо от того, равны ли их строки или нет, необходимы ли это для создания новых объектов, тем самым увеличивая бремя на программе.
С другой стороны, примечание: когда мы определяем класс, используя формат, такой как String Str = "ABC";, мы всегда считаем само собой разумеющимся, что создаем объект Str String Class. Беспокоитесь о ловушке! Объект, возможно, не был создан! И, может быть, просто укажите на объект, который был создан ранее. Только с помощью метода нового () мы можем убедиться, что новый объект создается каждый раз.
Несколько примеров проблемы с постоянным пулом строки
Пример 1:
Код Java
String s0 = "kvill"; string s1 = "kvill"; string s2 = "kv" + "ill"; system.out.println (s0 == s1); system.out.println (s0 == s2); Результат:
Анализ: во -первых, мы должны знать, что результат в том, что Java гарантирует, что строковая константа имеет только одну копию.
Поскольку S0 и S1 в примере являются константами строки, они определяются в течение периода компиляции, поэтому S0 == S1 правда; и «KV» и «Ill» также являются струнными постоянными. Когда строка подключена несколькими константами строки, она определенно является самой константой строки, поэтому S2 также проанализируется в константу строки в течение периода компиляции, поэтому S2 также является ссылкой на «Kvill» в постоянном пуле. Таким образом, мы получаем S0 == S1 == S2;
Пример 2:
Пример:
Код Java
Анализ: строки, созданные с помощью New String (), не являются постоянными и не могут быть определены в течение периода компиляции, поэтому строки, созданные New String (), не помещаются в постоянный пул, у них есть собственное адресное пространство.
S0 также является применением «Kvill» в постоянном пуле. S1 не может быть определен в течение периода компиляции, поэтому это ссылка на новый объект «Kvill», созданный во время выполнения. S2 не может быть определена в течение периода компиляции, потому что у него есть вторая половина новой строки («Ill»), поэтому это также применение вновь созданного объекта «kvill»; Если вы поймете это, вы узнаете, почему этот результат получен.
Пример 3:
Код Java
String a = "a1"; string b = "a" + 1; system.out.println ((a == b)); // result = true String a = "true"; string b = "a" + "true"; System.out.println ((a == b)); // result = true String a = "a3.4"; string b = "a" + 3.4; System.out.println ((a == b)); // result = true
Анализ: для подключения JVM констант строковых констант JVM оптимизирует соединение «+» постоянной строки к подключенному значению после периода компиляции программы. Возьмите «А» + 1 в качестве примера. После оптимизации компилятором это уже A1 в классе. В течение периода компиляции определяется значение строковой константы, поэтому конечный результат вышеуказанной программы верно.
Пример 4:
Код Java
String a = "ab"; string bb = "b"; string b = "a" + bb; system.out.println ((a == b)); // result = false
Анализ: для ссылок на строки в JVM, поскольку в подключении строк есть строковые ссылки, указанное значение не может быть определена в течение периода компиляции программы, то есть «A + BB не может быть оптимизирован компилятором, а только динамически распределяет и назначает подключенный новый адрес B в течение периода прогона программы. Следовательно, результат вышеуказанной программы является ложным.
Пример 5:
Код Java
String a = "ab"; final String bb = "b"; string b = "a" + bb; system.out.println ((a == b)); // result = true
Анализ: единственное различие между [4] заключается в том, что строка BB украшена окончательной модификацией. Для окончательных измененных переменных он проанализируется как локальная копия постоянного значения во время компиляции и хранится в своем собственном постоянном пуле или встроен в свой поток байт -кодов. Таким образом, в это время последствия « + BB и" A " +" B "одинаковы. Следовательно, результат вышеуказанной программы верен.
Пример 6:
Код Java
String a = "ab"; final String bb = getBb (); string b = "a" + bb; system.out.println ((a == b)); // result = falseprivate static String getBb () {return "b"; }Анализ: JVM ссылается на BB для строк, и его значение не может быть определена в течение периода компиляции. Только после вызова метода во время выполнения программы возвращаемое значение метода и «A» динамически подключены, а адрес назначен B. Следовательно, результат вышеуказанной программы является ложным.
О строке неизменно
Из приведенного выше примера мы можем узнать:
Строка s = "a" + "b" + "c";
Это эквивалентно строке S = "ABC";
Строка a = "a";
String b = "b";
Строка c = "c";
Строка s = a + b + c;
Это отличается, конечный результат равен:
Код Java
StringBuffer temp = new StringBuffer (); Temp.Append (a) .append (b) .append (c); string s = temp.toString ();
Из приведенных выше результатов анализа нетрудно сделать вывод, что строка использует оператор соединения (+) для анализа причины неэффективности, например, этот код:
Код Java
открытый класс тест {public static void main (string args []) {string s = null; for (int i = 0; i <100; i ++) {s+= "a"; }}}Каждый раз, когда + выполняется, создается объект StringBuilder, а затем добавляет его и выбрасывает его. В следующий раз, когда наступит цикл, объект StringBuilder будет восстановлен, а затем добавляет строку, и цикл завершается до тех пор, пока он не закончится. Если мы напрямую используем объект StringBuilder для добавления, мы можем сохранить N - 1 время для создания и уничтожения объекта. Следовательно, для приложений, которые требуют конкатенации строки в цикле, операция приложения обычно выполняется с использованием объектов StringBuffer или StringBulider.
Из -за неизменной природы класса струн, об этом есть что сказать. До тех пор, пока вы знаете, что экземпляр строки не будет изменяться после его генерирования, например: String Str = ”kv”+”ill”+«+» Ans »; Есть 4 строковых постоянных. Во -первых, «KV» и «Ill» генерируют «Kvill» в памяти, а затем «Kvill» и «» «генерируют« kvill »и« »и« kvill ans », генерируются; и адрес этой строки назначен STR, потому что строка« неизменная »генерирует много временных переменных, которые рекомендуется использовать StringBuffer, потому что строковой буффера.
Окончательное использование и понимание в строке
Код Java
final StringBuffer a = new StringBuffer ("111"); Final StringBuffer b = new StringBuffer ("222"); a = b; // Это предложение не компилируется, пока оно не будет закончено. Final StringBuffer a = new StringBuffer ("111"); A.Append ("222"); /// Скомпилируется после его завершенияМожно видеть, что окончательный действий действителен только для ссылки на «значение» (то есть адрес памяти). Это заставляет ссылку только указывать только на объект, на который был изначально указан. Изменение его указания приведет к ошибке времени компиляции. Что касается изменений в объекте, на который он указывает, конечно, безответственен.
Суммировать
Стек используется для хранения некоторых локальных данных переменных исходного типа данных и ссылок на объекты (строка, массив, объект и т. Д.), Но не хранит содержание объекта
Объекты, созданные с использованием нового ключевого слова, хранятся в куче.
Строка является специальным классом обертки, а ее ссылки хранятся в стеке, а содержимое объекта должно быть определена в соответствии с методом создания (постоянный пул и куча). Некоторые из них создаются во время компиляции и хранятся в бассейне «Постоянный строки», в то время как другие создаются только во время выполнения. Используйте новое ключевое слово и хранится в куче.
В приведенной выше статье кратко рассказывается о разнице между распределением памяти Java+ и местоположением хранилища переменной, которое я делюсь с вами. Я надеюсь, что вы можете дать вам ссылку, и я надеюсь, что вы сможете поддержать Wulin.com больше.