JavaRush /Курсы /Java Syntax Pro /Адресация памяти и переменные

Адресация памяти и переменные

Java Syntax Pro
2 уровень , 7 лекция
Открыта

1. Устройство памяти

У каждого компьютера есть оперативная память. Что же это такое, какими свойствами обладает и, самое главное, какая нам от этого польза?

Каждая программа (в том числе и программы, написанные на Java) перед выполнением загружается в оперативную память. В оперативной памяти находится код программы (который исполняется процессором) и данные программы (которые в память помещает сама программа).

Что же такое оперативная память и на что она похожа?

Представьте себе Excel 😎 Страница в Exсel'е состоит из ячеек, и у каждой ячейки есть её уникальный номер (A1, A2, ... B1, B2). Зная номер ячейки, всегда можно записать в неё какое-то значение или же получить значение, которое там хранится. Память компьютера устроена очень похоже.

Программа и её данные во время работы хранятся в памяти. Вся память компьютера представлена в виде маленьких ячеек – байт. У каждой ячейки есть её уникальный номер – 0, 1, 2, 3, ...; (нумерация начинается с нуля). Зная номер ячейки, мы можем сохранить в эту ячейку какие-то данные. Или взять их из неё. В одних ячейках хранится код программы – набор команд для процессора, в других – данные этой программы. Номер ячейки также называют адресом ячейки.

Процессор умеет исполнять команды из загруженной в память программы. Почти все команды процессора — это что-то типа: взять данные из некоторых ячеексделать с ними что-торезультат поместить в другие ячейки

Объединяя сотни простых команд, мы получаем сложные и полезные команды.

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

На заре компьютерной отрасли программы работали просто с номерами ячеек памяти, но потом для удобства программистов ячейкам стали давать имена. Уникальное имя переменной — это в первую очередь для удобства программистов: программа во время работы отлично справилась бы и с номерами.


2. Переменные в памяти

Всего в Java есть 4 типа данных для хранения целых чисел. Это byte, short, int и long.

Тип Размер, байт Происхождение имени
byte 1 Byte, т.к. занимает один байт памяти
short 2 Сокращение от Short Integer
int 4 Сокращение от Integer
long 8 Сокращение от Long Integer

Также в Java есть 2 вещественных типа — float и double:

Тип Размер, байт Происхождение имени
float 4 Сокращение от Floating Point Number
double 8 Сокращение от Double Float

Каждый раз, когда выполнение программы доходит до команды создания переменной, ей выделяется небольшая область памяти (размер зависит от типа переменной).

Адресом переменной считается адрес первой ячейки выделенного под нее блока памяти.

Java-программам запрещено напрямую обращаться к памяти. Вся работа с памятью происходит только через Java-машину.


3. Тип String в памяти

Тип String может хранить большие объемы данных, поэтому это не просто тип данных, а полноценный класс.

Сами данные типа String (текст) помещаются в специальный объект, под который выделяется память, а уже адрес этого объекта помещается в переменную, под которую тоже выделяется память.

Переменная a типа int занимает 4 байта и хранит значение 1.

Переменная b типа int занимает 4 байта и хранит значение 10,555. Запятая - это не дробная часть числа, а разделение разрядов. Дробная часть отделяется точкой

Переменная d типа double занимает 8 байт и хранит значение 13.001.

Переменная str типа String занимает 4 байта и хранит значение G13 — адрес первой ячейки объекта, содержащего текст.

Объект типа String (содержащий текст) хранится отдельным блоком памяти. Адрес его первой ячейки хранится в переменной str.


4. Почему в программировании всё нумеруют с нуля

Люди очень часто удивляются, почему в программировании почти везде принято считать с нуля. Дело в том, что есть очень много ситуаций, когда считать с нуля удобнее (хотя есть и ситуации, когда удобнее считать с 1).

Самая простая из таких ситуаций — это адресация памяти. Если вашей переменной выделили 4 байта памяти и у вас есть X – адрес первого байта, то какие будут адреса у всех байтов? X+0, X+1, X+2, X+3. Вот мы уже и получили группу байтов с индексами 0, 1, 2, 3.

Когда мы думаем об относительном адресе внутри какого-либо блока данных, всегда получаем нумерацию с нуля. Это и есть первая и самая распространенная причина счета с нуля.



Комментарии (286)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
29 марта 2025
Жду бесплатных задач день 1
Kirill Kochetov Уровень 32
7 марта 2025
Старт 07.03.25
Sergey Frolov (Sergey F.) Уровень 3
5 марта 2025
Как по нотам! Играем дальше))
Кирилл Фишер Уровень 5
19 февраля 2025
Хоть убейте, не понял про счет от 0. Пример в разделе 4 этой лекции, оказался для меня ненаглядным.
Barabulka Уровень 4
19 февраля 2025
*Адресом переменной считается адрес первой ячейки выделенного под нее блока памяти. Остальное - смещение. Относительно самого числа, его первый байт уже находится в какой-то ячейке и смещения нет (=0), а что бы найти следующий байт этого числа надо к начальной нулевой позиции прибавить 1. отсюда у 4х байтового числа индексы не от 1 до 4 , а от 0 до 3
Linx Уровень 3
24 января 2025
подскажите (ставлю лайк :) ) 1. Если метод ".length" ставиться после значения => "look".length(); то в каких случаях влаживаеться аргумент в скобки? 2. Для чего выделяется аж 4 байта только для ССЫЛКИ на строку String ?
Anonymous #3546156 Уровень 4
3 февраля 2025
1 в теме циклов и массивов про это будет 2 сейчас уже не нужно думать про байты, это важно было 20 лет назад
5 мая 2025
Исходя из базовой инфы, с которой я столкнулся при поверхностном начальном уровне изучения информатики могу предположить, что раз в ячейке хранится адрес другой ячейки, то тут надо смотреть на каком проце и ос запускается прога, адреса то могут быть 32 или 64 битными, хотя это только мои предположения )))
Unbelievable Уровень 8
4 января 2025
А зачем такие сложности с хранением String? Почему не выделяется точно также область и значение не пишется туда напрямую? Зачем нужна система, где мы сначала создаём одну коробку и в неё кладём другую коробку уже с наполнением? Посоветуйте, пожалуйста, лекции или печатный материал на эту тему, кто может. Я просто пока не особо понимаю в чём профит такого типа хранения. По сути только памяти больше занимает.
kaidzualex Уровень 5 Expert
7 января 2025
Это связано с тем что мы JVM не может знать размер строки, которую пользователь внесет в переменную. В будущем будет куда понятнее, когда будут разбираться списки и массивы данных. Такой метод хранения применим только к примитивным типам, а в случае со сложными типами(отдельными классами, которые начинаются с большой буквы: String, ArrayList и т.д.) они не применяются. Можно посмотреть лекции про управление памятью в Java, но я бы не стал туда залазить. Совершенно не обязательно знать как все работает под капотом, главное понимать принцип. Информации в курсе и без того будет предостаточно. Удачи!
Unbelievable Уровень 8
8 января 2025
Спасибо! Да, действительно, теперь когда вы сказали про размер строки, это стало практически очевидным)) Даже не знаю чего сама не подумала. Спасибо за разъяснение!
5 мая 2025
К сожалению это не отчечает на вопрос, ибо по какому то адресу все равно записывается, какой бы ни был размер, и да, о каком принципе идет речь, я что то не пойму.
Valentine Уровень 3
9 мая 2025
Дело в самой строке. Компьютер не видит ни цифр, ни букв. Для него они все — последовательность 0 и 1. И если примитивные типы можно представить как фиксированную последовательность, то тип String является последовательностью из char (в 9 Java это последовательность byte). Например, тип byte занимает 1 байт памяти, т.е. максимально возможно значение будет либо 255 (если нет знака), либо 127 (если есть знак). В строке же мы можем хранить значение любой длинны, т.е. оно может быть из 200 байт, 1000 байт или любого другого размера. Пример: int a; // Переменная типа int с четким размером в 4 байта String str; // Переменная типа String, но размер ее неизвестен a = 372882; // число в диапазоне, ошибки нет str = "абв"; // строка занимает определенное количество байт a = 2147483648; // число превышает допустимое значение, произойдет переполнение и Java некорректно сохранит данные str = "sioekdndjdld" // строка увеличила кол-во занимаемых байт, но ошибку мы не получили
9 мая 2025
Суть моего вопроса была в том, что знает jvm или нет, как вы написали, это всë последовательность байтов, однако данные типа String будут записаны по какому то, но адресу, так же известно, что вместо имен переменных подставляются в конченом итоге адреса, в итоге мы по любому получаем адрес, но почему в адрес который подставляется заместо имени переменной типа String, нельзя начать записывать эти последовательности байт? а вместо этого по этому адресу записывается адрес, по которому записываются все эти байты, какая разница? ведь что там, что там, оба - адреса, в один адрес джава "всемогуще" может, а в дрогой нет, вот в чем суть вопроса.
Valentine Уровень 3
10 мая 2025
Вы не учитываете особенности реализации и оптимизации. String — ссылочный тип. Что это значит? Это значит, что две переменные с одинаковым значением будут обращаться к одной ячейке в памяти, в отличие от примитивных типов, где значение хранится непосредственно в ячейке памяти. Для примера: Есть ячейки A, B, C Создадим переменную imNumber с типом int — она будет записана в ячейку A. Создадим ещё одну переменную с типом imTooNumber с типом int — она попадет в ячейку B. Как мы видим, данные в разных ячейках. Что же насчёт String? Создадим переменную imString и запишем туда строку "Я строка" (это где-то 15 байтов) — она записана в ячейку C. А теперь создадим новую переменную типа String и назовем её imTooString и запишем туда такое же значение(String imTooString = "Я строка";). Что сделает Java? Вместо копирования 15 байтов, она просто передаст переменной imTooString ссылку на уже существующие данные. Заметка: Если что Java хранит значения строк в отдельном месте — String Pool.
11 мая 2025
Я спрашивал не о том, что такое ссылочный и примитивный типы, а спрашивал, почему нельзя сохранять как в примитивах, если нет технических ограничений в теории, то для чего оно реализовано так, как реализовано на практике? Что бы повысить эффетивность затрат русурсов, повышения скорости и т.п.? Ведь разработчики джавы тоже не дураки, очевидно же, что какую то цель конкретную этим преследовали, но какую? Вот тут хотелось бы по всем причинам пройтись, но по верхам, на уровне идей, а не инфу от том, как там работает ссылочный тип дотошно мулолить.
Valentine Уровень 3
11 мая 2025
Я уже несколько раз сказал об оптимизации ресурсов. Благодаря тому, что в ячейку не записываются данные — они как минимум не дублируются (специально привел пример работы ссылочных типов и примитивных). Если следовать вашей логике и располагать строки в ячейке, вот что мы получим: Есть 25 одинаковых строк в разных переменных, размером 20 байт. 20 * 25 = 500 байт, а это многовато. Теперь представьте, что таких строк ещё больше, как вы думаете, какими словами вспомнит вас пользователь, когда его компьютер начнет нагреваться? Кроме того, я опять повторюсь про динамический размер. Вы почему-то считаете, что это ничего не объясняет, как раз-таки объясняет. Как зарезервировать место для чего-то, размера чего ты не знаешь? А если не хватит? А если много будет? Нельзя взять и записать в 2 байта памяти все 10. Это вам станет понятно, когда вы дойдете до устройства памяти и таких понятий как стек и куча.
12 мая 2025
"Если следовать вашей логике и располагать строки в ячейке" - это не моя логика, а часть вопроса. "Вы почему-то считаете, что это ничего не объясняет" - наверное потому что для меня оно ничего не объясняет, так понятней? )) и к тому же на самом деле тут была подмена тезиса/вопроса, по этому паралогизм предпочту проигнорить. Последнюю часть вашего ответа я вообще не понял, что значит, не знает? В общем и целом так то процессор и другие железки вообще ничего не знают, они рабы, которые выполняют приказы и всë. При команде процессору для вснесения данных в озу, мы используем приемник и источник, то есть всегда нужно четко указывать что и куда и в каком количестве надо, вы ассесблер изучали? архитектуру процов? при чем тут модели памяти типа кучи и стека, в контексте ответа на вопрос о самой мотивации в конкретной реализации идей, что реализованы в джаве? озу это просто железка, там внутри нет деления на стек и куча, это всего лишь модели хранения и когда я спрашивал при чем тут это, я имел ввиду, что рассказ об устройте модели памяти и типов, то есть того как хранится, не тождественен рассказу и объяснению почему оно так, как описывается, хранится. Если процу явно указали что делать, то он не может не "знать" что именно делать, а раз данные строковые уже занесены, то значит этому предшествовала команда, и такое можно повторять до бесконесности, либо занимая память свободную, либо занося с перезаписью в те же ячейки. Как я понял вы говорите по большей степени о компиляции, о лексическом анализе, если у вас действительно есть в этом знания, то объясните подробнее и внятнее, просто то у вас то про железку, то есть озу/ячейки/байты, то про компиляцию, может быть вы что то и понимаете, но у вас плохо получается это до меня донести, так как витиеватая смесь с полу инфой, то о работе компилятора, то железки, в следствии чего толком глубоко в суть погрузиться не удается. Кстати, а какая разница между аппаратным и программным стеком? Нужено ли иметь аппаратную реадизацию стека
12 мая 2025
в комментарий один не уместилось: нужен ли аппаратный стек для реализации программного? Если в системе с аппаратной реализацией стека, мы хотим с помощью какого либо языка программирования реализовать программный стэк, то обязательно ли при это задействуется аппаратный?
Valentine Уровень 3
12 мая 2025
Начнем с того, что понятие стек и куча про JVM, а не про аппаратный стек. У JVM свой стек и своя куча. Не знаю для чего вы приплели аппаратный стек, но отвечу сразу: программный стек не обязан использовать аппаратный стек. И да вы можете реализовать свой стек без аппаратного стека. Ваш вопрос первоначально звучал так: Если мы записываем в какой-то адрес значение строки, то зачем нам записывать ссылку куда-то отдельно? Мой ответ: все примитивы и ссылки хранятся в стеке JVM, так как имеют четкий размер (да, у ссылок четкий размер), а стек в свою очередь тоже ограничен в размере 1 МБ (по умолчанию). Я говорю, если что, о стеке JVM, а не о железе компьютера. Стек в разы быстрее чем куча, он легко очищается, но он четко ограничен в размерах, поэтому в стек нельзя поместить то, размер чего не известен (String).
Антон Копанев Уровень 13
26 декабря 2024
В статье упоминаются примитивные типы данных, но не приводятся их точные диапазоны. Для полного понимания работы с переменными полезно знать размеры и диапазоны значений этих типов: Знание этих диапазонов помогает выбирать подходящий тип данных для хранения значений в переменных.
22 декабря 2024
На java можно же написать калькулятор который будет считать ну например до 10 миллиардов? Ну или не калькулятор, а скажем кошелек для крипты?
23 декабря 2024
да можно)) просто не используй int, а используй long и библиотеки типа BigInteger
Zl_oy Уровень 7
24 января 2025
просто огонь!!! Вы настоящий программер, ответили на свой же вопрос, чтобы вы из будущего, когда будет вспоминать, как выполнить ту или иную задачу мог посмотреть на СВОЙ же вопрос и и СВОЙ же ответ :-)
Виктор Ш Уровень 72
12 декабря 2024
Главное не сдаваться )) Повторение - мать учения )) И это 100% касается программирования ))
Sergey Frolov (Sergey F.) Уровень 3
9 декабря 2024
Ошибки в основном синтаксические! Но так и должно быть на этом курсе =)