JavaRush /Курси /Kotlin SELF /Адресація памʼяті та змінні

Адресація памʼяті та змінні

Kotlin SELF
Рівень 2 , Лекція 4
Відкрита

1. Будова памʼяті

У кожного компʼютера є оперативна памʼять. Що це таке, які вона має властивості і, найголовніше, яка з цього користь для нас?

Кожна програма (зокрема й програми, написані на Kotlin) перед виконанням завантажується в оперативну памʼять. В оперативній памʼяті є код програми (його виконує процесор) і дані програми (їх у памʼять записує сама програма).

То що ж таке оперативна памʼять і на що вона схожа?

Уявіть собі Excel. Аркуш Excel складається з комірок, і кожна комірка має унікальний номер (A1, A2, B1, B2). Знаючи номер комірки, ви завжди можете записати в неї якесь значення або отримати те, що там зберігається. Памʼять компʼютера влаштована схожим чином.

memory-excel

Під час роботи програма та її дані зберігаються в памʼяті. Уся памʼять компʼютера подана у вигляді маленьких комірок — байтів. Кожна комірка має унікальний номер — 0, 1, 2, 3, (нумерація починається з нуля). Знаючи номер комірки, ми можемо зберегти в ній якісь дані або прочитати їх. В одних комірках зберігається код програми — набір команд для процесора, в інших — дані цієї програми. Номер комірки також називають адресою комірки.

Процесор уміє виконувати команди із програми, завантаженої в памʼять. Майже всі команди процесора — це щось на кшталт: взяти дані з певних комірокзробити з ними щось → результат помістити в інші комірки.

Обʼєднуючи сотні простих команд, ми отримуємо складні й корисні дії.

Коли в коді програми оголошується змінна, для неї виділяється шматочок іще не використаної памʼяті. Зазвичай це кілька байтів. Під час оголошення змінної обовʼязково потрібно вказати тип інформації, яку програма зберігатиме в ній: числа, текст або інші дані. Без знання типу незрозуміло, якого розміру блок памʼяті потрібно виділити під змінну.

На зорі компʼютерної індустрії програми працювали просто з номерами комірок памʼяті. Згодом, для зручності програмістів, коміркам почали давати імена. Унікальне імʼя змінної потрібне насамперед для зручності: програма під час роботи чудово впоралася б і з номерами.

2. Змінні в памʼяті

У Kotlin є чотири основні типи даних для зберігання цілих чисел. Це Byte, Short, Int і Long.

Тип Розмір, байт Походження назви
Byte
1
Byte, оскільки займає один байт памʼяті
Short
2
Скорочення від Short Integer
Int
4
Скорочення від Integer
Long
8
Скорочення від Long Integer

Також у Kotlin є два дійсні типи — Float і Double:

Тип Розмір, байт Походження назви
Float
4
Скорочення від Floating Point Number
Double
8
Скорочення від Double Float

Щоразу, коли виконання програми доходить до команди створення змінної, для неї виділяється невелика ділянка памʼяті (її розмір залежить від типу змінної).

Важливо!

Адресою змінної вважається адреса першої комірки блоку памʼяті, виділеного під неї.

Kotlin-програмам заборонено безпосередньо звертатися до памʼяті. Уся робота з памʼяттю відбувається лише через віртуальну машину (JVM).

3. Тип String у памʼяті

Тип String може зберігати великі обсяги даних, тож це не просто тип даних, а повноцінний обʼєкт.

Самі дані типу String (текст) поміщаються в спеціальний обʼєкт, під який виділяється памʼять. А вже адресу цього обʼєкта записують у змінну, під яку теж виділяється памʼять.

memory-string

  • Змінна a типу Int займає 4 байти й зберігає значення 1.
  • Змінна b типу Int займає 4 байти й зберігає значення 10_555. У звичайних текстах числа іноді записують як 10 555, де пробіл — це не дробова частина, а розділювач розрядів. У коді Kotlin для розділення розрядів можна використовувати символ _. Дробову частину відокремлюють крапкою.
  • Змінна d типу Double займає 8 байтів і зберігає значення 13.001.
  • Змінна str типу String зберігає значення D12 — адресу першої комірки обʼєкта, що містить текст.

Обʼєкт типу String (який містить текст) зберігається окремим блоком памʼяті. Адреса його першої комірки зберігається в змінній str.

4. Що відбувається, коли ми присвоюємо

Ще одна важлива річ — як працює присвоювання. Наприклад:

fun main() {
    val a = 10
    var b = a
    b = 20
    println(a) // 10
}

У цьому прикладі в памʼяті створюються дві комірки: одна для a, друга — для b. Коли ми пишемо b = a, копіюється значення (10), а не сам «ящик». Зміни в b ніяк не впливають на a.

Тепер аналогічно, але з рядками:

fun main() {
    val s1 = "Hello"
    var s2 = s1
    s2 = s2 + " World"
    println(s1) // "Hello"
    println(s2) // "Hello World"
}

Тут обидві змінні s1 і s2 посилаються на один і той самий рядок "Hello" — до моменту зміни. Але коли ми виконуємо s2 = s2 + " World", для s2 створюється новий рядок "Hello World", а s1, як і раніше, вказує на старий рядок "Hello".

5. Чому в програмуванні все нумерують із нуля

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

Спробую підібрати аналогію. Уявіть, що ви стоїте в довгій черзі в магазині. І тут касир каже: усі покупці, починаючи з 20-го, нехай переходять на другу касу. Які будуть у них номери? 20, 21, 22, 23, Логічно. А якщо відраховувати від 20-го? 0, 1, 2, 3,

Коли ми задаємо групу як «номер першого елемента» + «кількість», то всередині групи відносні номери виходять +0, +1, +2,

У програмуванні — те саме. Якщо вашій змінній виділили 100 байтів памʼяті й у вас є X — адреса першого байта, то які будуть адреси в усіх байтів? X+0, X+1, X+2, , X+99. Ось ми й отримали групу байтів з індексами 0, 1, 2, 99.

Коли ми думаємо про відносну адресу всередині будь-якого блока даних, ми майже завжди отримуємо нумерацію з нуля. Це й є перша та найпоширеніша причина рахунку з нуля.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ