Java Memory Model (JMM)
Java Memory Model (JMM) определяет, как изменения в памяти, производимые одним потоком, становятся видимыми другим потокам. JMM описывает:
Как потоки взаимодействуют с основной памятью.
Правила синхронизации доступа к переменным.
Гарантии порядка операций, чтобы избежать непредсказуемого поведения в многопоточном программировании.
Главной целью JMM является устранение несогласованности данных и определение поведения программы на уровне видимости и порядка выполнения операций в многопоточной среде.
Основные концепции JMM
Главная (основная) память (Main Memory):
Это область памяти, где хранятся все общие переменные (поля классов, статические переменные и т. д.).
Каждому потоку также выделяется собственная локальная память (Thread Local Memory), где временно сохраняются копии значений переменных.
Кэширование и локальная память потоков:
Потоки могут не сразу обращаться к основной памяти. Вместо этого они используют кэш или локальную копию переменных.
Изменения, сделанные в локальной памяти одного потока, могут не быть видны другим потокам, если они не будут синхронизированы с основной памятью.
Гарантии видимости и упорядочение:
Видимость означает, что если один поток изменил переменную, другой поток сможет увидеть это изменение.
Упорядочение операций гарантирует, что инструкции выполняются в предсказуемом порядке.
Инструкции и пересортировка:
Компилятор и процессор могут менять порядок выполнения операций для оптимизации.
Например, две независимые операции могут поменяться местами, если это ускорит выполнение программы. JMM устанавливает правила, чтобы такая пересортировка не нарушала корректность многопоточной программы.
#Java #Training #Medium #JMM
Java Memory Model (JMM) определяет, как изменения в памяти, производимые одним потоком, становятся видимыми другим потокам. JMM описывает:
Как потоки взаимодействуют с основной памятью.
Правила синхронизации доступа к переменным.
Гарантии порядка операций, чтобы избежать непредсказуемого поведения в многопоточном программировании.
Главной целью JMM является устранение несогласованности данных и определение поведения программы на уровне видимости и порядка выполнения операций в многопоточной среде.
Основные концепции JMM
Главная (основная) память (Main Memory):
Это область памяти, где хранятся все общие переменные (поля классов, статические переменные и т. д.).
Каждому потоку также выделяется собственная локальная память (Thread Local Memory), где временно сохраняются копии значений переменных.
Кэширование и локальная память потоков:
Потоки могут не сразу обращаться к основной памяти. Вместо этого они используют кэш или локальную копию переменных.
Изменения, сделанные в локальной памяти одного потока, могут не быть видны другим потокам, если они не будут синхронизированы с основной памятью.
Гарантии видимости и упорядочение:
Видимость означает, что если один поток изменил переменную, другой поток сможет увидеть это изменение.
Упорядочение операций гарантирует, что инструкции выполняются в предсказуемом порядке.
Инструкции и пересортировка:
Компилятор и процессор могут менять порядок выполнения операций для оптимизации.
Например, две независимые операции могут поменяться местами, если это ускорит выполнение программы. JMM устанавливает правила, чтобы такая пересортировка не нарушала корректность многопоточной программы.
#Java #Training #Medium #JMM
Правила JMM для взаимодействия потоков
JMM включает несколько базовых правил для обеспечения корректного поведения программы:
Правило Happens-Before:
Если одна операция происходит "раньше" другой с точки зрения JMM, это означает, что все изменения, сделанные первой операцией, будут видны второй.
Например, вызов Thread.start() имеет отношение happens-before к всем действиям внутри нового потока.
Правило синхронизации (synchronized блоки):
Использование ключевого слова synchronized гарантирует, что все изменения, сделанные внутри блока, будут видны другим потокам после выхода из него.
Volatile-переменные:
Использование ключевого слова volatile указывает, что изменения в этой переменной немедленно записываются в основную память.
volatile гарантирует видимость, но не упорядочение операций.
Конструкторы и финализация:
Все операции, выполненные в конструкторе, должны быть завершены до того, как ссылка на объект станет доступной другим потокам.
Это правило предотвращает "полуинициализированные" объекты в многопоточной среде.
Внутреннее устройство JMM и управление памятью
На уровне устройства, JMM опирается на низкоуровневую архитектуру процессора и системы памяти:
Слабая консистентность памяти:
Современные процессоры и системы используют слабую консистентность, где чтение и запись могут происходить асинхронно для оптимизации.
JMM компенсирует это ограничение, обеспечивая строгие правила синхронизации.
Барьеры памяти (Memory Barriers):
JMM вводит так называемые барьеры памяти (memory barriers или fences) для обеспечения правильного порядка операций.
Существуют два типа барьеров:
Барьеры записи (Write Barrier) — гарантируют, что все предшествующие записи переменных видны другим потокам.
Барьеры чтения (Read Barrier) — гарантируют, что все последующие операции чтения переменных происходят после предыдущих операций записи.
Пересортировка (Reordering):
Компилятор и процессор могут изменять порядок инструкций для повышения производительности.
Final-поля:
Поля, объявленные как final, имеют особые гарантии: они инициализируются до того, как объект станет доступен другим потокам.
Это предотвращает утечки ссылок на не полностью инициализированные объекты.
Пример нарушения JMM
Рассмотрим типичную проблему гонки данных:
Правильное использование JMM
Для обеспечения корректности программы в многопоточной среде можно использовать следующие механизмы:
Использование synchronized для метода increment():
#Java #Training #Medium #JMM
JMM включает несколько базовых правил для обеспечения корректного поведения программы:
Правило Happens-Before:
Если одна операция происходит "раньше" другой с точки зрения JMM, это означает, что все изменения, сделанные первой операцией, будут видны второй.
Например, вызов Thread.start() имеет отношение happens-before к всем действиям внутри нового потока.
Правило синхронизации (synchronized блоки):
Использование ключевого слова synchronized гарантирует, что все изменения, сделанные внутри блока, будут видны другим потокам после выхода из него.
class Counter {
private int count = 0;
public synchronized void increment() {
count++; // Этот блок синхронизирован, изменения видны другим потокам.
}
public synchronized int getCount() {
return count;
}
}
Volatile-переменные:
Использование ключевого слова volatile указывает, что изменения в этой переменной немедленно записываются в основную память.
volatile гарантирует видимость, но не упорядочение операций.
class FlagExample {
private volatile boolean flag = false;
public void setFlagTrue() {
flag = true;
}
public void checkFlag() {
if (flag) {
System.out.println("Flag is true!");
}
}
}
Конструкторы и финализация:
Все операции, выполненные в конструкторе, должны быть завершены до того, как ссылка на объект станет доступной другим потокам.
Это правило предотвращает "полуинициализированные" объекты в многопоточной среде.
Внутреннее устройство JMM и управление памятью
На уровне устройства, JMM опирается на низкоуровневую архитектуру процессора и системы памяти:
Слабая консистентность памяти:
Современные процессоры и системы используют слабую консистентность, где чтение и запись могут происходить асинхронно для оптимизации.
JMM компенсирует это ограничение, обеспечивая строгие правила синхронизации.
Барьеры памяти (Memory Barriers):
JMM вводит так называемые барьеры памяти (memory barriers или fences) для обеспечения правильного порядка операций.
Существуют два типа барьеров:
Барьеры записи (Write Barrier) — гарантируют, что все предшествующие записи переменных видны другим потокам.
Барьеры чтения (Read Barrier) — гарантируют, что все последующие операции чтения переменных происходят после предыдущих операций записи.
Пересортировка (Reordering):
Компилятор и процессор могут изменять порядок инструкций для повышения производительности.
int x = 0, y = 0;
x = 1; // A
y = x + 1; // B
// Компилятор может поменять A и B местами, если это ускоряет выполнение.
Final-поля:
Поля, объявленные как final, имеют особые гарантии: они инициализируются до того, как объект станет доступен другим потокам.
Это предотвращает утечки ссылок на не полностью инициализированные объекты.
Пример нарушения JMM
Рассмотрим типичную проблему гонки данных:
class SharedObject {
private int counter = 0;
public void increment() {
counter++; // Несинхронизированный доступ к переменной.
}
public int getCounter() {
return counter;
}
}
Если несколько потоков одновременно вызывают метод increment, результат может быть непредсказуемым из-за отсутствия синхронизации: один поток может перезаписать значение, измененное другим потоком.
Правильное использование JMM
Для обеспечения корректности программы в многопоточной среде можно использовать следующие механизмы:
Использование synchronized для метода increment():
public synchronized void increment() {
counter++;
}
Применение AtomicInteger для безопасного инкремента:
java
Копировать код
import java.util.concurrent.atomic.AtomicInteger;
class SharedObject {
private AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet(); // Безопасная атомарная операция.
}
public int getCounter() {
return counter.get();
}
}
#Java #Training #Medium #JMM
This media is not supported in your browser
VIEW IN TELEGRAM
Всем доброго утра!🖐
Сегодня в 16:00 по МСК, мы вновь соберемся, что покодить)))
Сегодня мы напишем чат, и попробуем запустить его для работы через удаленный сервер! 😱
Жду всех, будет интересно!)✊
Сегодня в 16:00 по МСК, мы вновь соберемся, что покодить)))
Сегодня мы напишем чат, и попробуем запустить его для работы через удаленный сервер! 😱
Жду всех, будет интересно!)✊
Создаем свой чат! Размещаем его на удаленном сервере.
Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE
Спасибо огромное тем кто пришел, я правда старался для Вас) Надеюсь все понравилось! 🙏
На сегодняшней встрече с подписчиками, мы создали клиент - серверный чат, и разместили сервер чата на удаленном виртуальном сервере! Рассмотрели на примере работу с библиотекой Swing, классом Socket и многопоточкой)))
Код на GitHUB - https://github.com/Oleborn/ChatProject.git
Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!
Всем хорошего вечера и отличного общения! 🫡✌️
Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE
Спасибо огромное тем кто пришел, я правда старался для Вас) Надеюсь все понравилось! 🙏
На сегодняшней встрече с подписчиками, мы создали клиент - серверный чат, и разместили сервер чата на удаленном виртуальном сервере! Рассмотрели на примере работу с библиотекой Swing, классом Socket и многопоточкой)))
Код на GitHUB - https://github.com/Oleborn/ChatProject.git
Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!
Всем хорошего вечера и отличного общения! 🫡✌️
Сборка мусора в Java
Сборка мусора (Garbage Collection, GC) — это автоматический процесс управления памятью, который освобождает объекты, больше не используемые программой. Главная задача GC — найти объекты, которые недостижимы, и освободить занимаемую ими память для повторного использования. Программистам в Java не нужно вручную управлять выделением и освобождением памяти (как, например, в языках C/C++), что значительно упрощает разработку и снижает количество ошибок, связанных с утечками памяти.
Память в Java разделена на две основные части: кучу (Heap) и стек (Stack). Объекты, создаваемые динамически (например, при вызове new), размещаются в куче и занимают определенное место до тех пор, пока они не станут недостижимыми. Если ненужные объекты не будут удаляться, память заполнится, что приведет к сбою программы из-за OutOfMemoryError.
Garbage Collector автоматически отслеживает и удаляет такие объекты, поддерживая память в чистоте и предотвращая утечки.
Основные концепции сборки мусора
Перед тем как погрузиться в детали, рассмотрим несколько ключевых понятий, связанных с управлением памятью в Java:
Достижимость объектов:
Объект считается достижимым, если на него есть ссылки из активных частей программы (например, глобальные переменные или переменные метода).
Недостижимый объект — это объект, на который нет ссылок, и он не может быть использован в дальнейшем.
Корни GC (GC Roots):
GC Roots — это специальные точки входа, от которых начинается проверка достижимости объектов.
Примеры GC Roots: активные потоки, статические поля классов, локальные переменные методов, ссылки из JNI (Java Native Interface).
Алгоритмы сборки мусора:
Существуют различные алгоритмы для отслеживания достижимости объектов: маркировка и удаление (Mark and Sweep), копирование (Copying), сжатие (Compaction) и другие.
Алгоритмы также могут отличаться по стратегии: минорная (Minor GC) и полная сборка (Full GC).
Молодое и старое поколения (Young и Old Generation):
Java-куча делится на несколько регионов:
Young Generation — область, в которой создаются новые объекты. В эту область чаще всего попадает сборка мусора.
Old Generation — сюда перемещаются более «долгоживущие» объекты. Сборка в этом регионе происходит реже, но является более затратной.
Как работает сборка мусора в JVM?
Java использует комбинацию разных алгоритмов и стратегий для эффективного управления памятью:
Mark and Sweep:
Основной алгоритм, используемый в большинстве JVM.
Маркировка (Mark): GC проходит по всем доступным объектам и помечает их как "достижимые".
Удаление (Sweep): Все объекты, которые не были помечены, удаляются.
Copying:
Этот алгоритм используется в Eden-области (молодое поколение).
Вся Young Generation делится на Eden и два Survivor пространства (From и To).
Когда Eden заполняется, GC перемещает все активные объекты в Survivor To область и очищает Eden.
Generational Garbage Collection:
JVM разделяет память на разные поколения:
Young Generation — для новых объектов.
Old Generation — для объектов, которые пережили несколько сборок.
Объекты перемещаются из Young в Old по мере увеличения их "возраста".
Compact and Defragmentation:
После удаления недостижимых объектов память может стать фрагментированной.
Для предотвращения фрагментации, GC может выполнять сжатие (compaction), перемещая объекты в соседние участки памяти.
#Java #Training #Medium #Garbage_collector
Сборка мусора (Garbage Collection, GC) — это автоматический процесс управления памятью, который освобождает объекты, больше не используемые программой. Главная задача GC — найти объекты, которые недостижимы, и освободить занимаемую ими память для повторного использования. Программистам в Java не нужно вручную управлять выделением и освобождением памяти (как, например, в языках C/C++), что значительно упрощает разработку и снижает количество ошибок, связанных с утечками памяти.
Память в Java разделена на две основные части: кучу (Heap) и стек (Stack). Объекты, создаваемые динамически (например, при вызове new), размещаются в куче и занимают определенное место до тех пор, пока они не станут недостижимыми. Если ненужные объекты не будут удаляться, память заполнится, что приведет к сбою программы из-за OutOfMemoryError.
Garbage Collector автоматически отслеживает и удаляет такие объекты, поддерживая память в чистоте и предотвращая утечки.
Основные концепции сборки мусора
Перед тем как погрузиться в детали, рассмотрим несколько ключевых понятий, связанных с управлением памятью в Java:
Достижимость объектов:
Объект считается достижимым, если на него есть ссылки из активных частей программы (например, глобальные переменные или переменные метода).
Недостижимый объект — это объект, на который нет ссылок, и он не может быть использован в дальнейшем.
Корни GC (GC Roots):
GC Roots — это специальные точки входа, от которых начинается проверка достижимости объектов.
Примеры GC Roots: активные потоки, статические поля классов, локальные переменные методов, ссылки из JNI (Java Native Interface).
Алгоритмы сборки мусора:
Существуют различные алгоритмы для отслеживания достижимости объектов: маркировка и удаление (Mark and Sweep), копирование (Copying), сжатие (Compaction) и другие.
Алгоритмы также могут отличаться по стратегии: минорная (Minor GC) и полная сборка (Full GC).
Молодое и старое поколения (Young и Old Generation):
Java-куча делится на несколько регионов:
Young Generation — область, в которой создаются новые объекты. В эту область чаще всего попадает сборка мусора.
Old Generation — сюда перемещаются более «долгоживущие» объекты. Сборка в этом регионе происходит реже, но является более затратной.
Как работает сборка мусора в JVM?
Java использует комбинацию разных алгоритмов и стратегий для эффективного управления памятью:
Mark and Sweep:
Основной алгоритм, используемый в большинстве JVM.
Маркировка (Mark): GC проходит по всем доступным объектам и помечает их как "достижимые".
Удаление (Sweep): Все объекты, которые не были помечены, удаляются.
Copying:
Этот алгоритм используется в Eden-области (молодое поколение).
Вся Young Generation делится на Eden и два Survivor пространства (From и To).
Когда Eden заполняется, GC перемещает все активные объекты в Survivor To область и очищает Eden.
Generational Garbage Collection:
JVM разделяет память на разные поколения:
Young Generation — для новых объектов.
Old Generation — для объектов, которые пережили несколько сборок.
Объекты перемещаются из Young в Old по мере увеличения их "возраста".
Compact and Defragmentation:
После удаления недостижимых объектов память может стать фрагментированной.
Для предотвращения фрагментации, GC может выполнять сжатие (compaction), перемещая объекты в соседние участки памяти.
#Java #Training #Medium #Garbage_collector
Типы сборок мусора в Java
JVM поддерживает несколько типов сборок мусора, каждый из которых предназначен для определенного типа приложений:
Serial GC:
Использует один поток для выполнения всех операций GC.
Подходит для однопоточных приложений или программ с небольшими кучами.
Parallel GC (или Throughput Collector):
Использует несколько потоков для сборки мусора.
Хорош для многопоточных приложений, стремящихся минимизировать время пауз.
CMS (Concurrent Mark-Sweep):
Предназначен для минимизации пауз при сборке мусора.
Выполняет маркировку и удаление объектов одновременно с выполнением программы.
Более ресурсоемкий и требует больше CPU.
G1 (Garbage First):
Продвинутый сборщик, ориентированный на минимизацию пауз.
Делит память на множество регионов и выполняет сборку в приоритетных областях.
ZGC и Shenandoah:
Современные сборщики мусора с низкими паузами.
Ориентированы на большие кучи и высокую производительность.
Особенности сборки мусора в разных регионах памяти
Память в JVM делится на несколько регионов, каждый из которых имеет свои особенности:
Young Generation:
Основные области: Eden, Survivor From, Survivor To.
В этой области происходят минорные сборки (Minor GC) — сборки, которые удаляют недостижимые объекты в молодом поколении.
Old Generation:
Сюда попадают объекты, которые "пережили" несколько минорных сборок.
Сборка в этой области называется Full GC или Major GC и является более затратной по времени.
Permanent Generation (Metaspace):
Содержит метаинформацию, загружаемые классы и методы.
В более новых версиях JVM (с Java 8) эта область была заменена на Metaspace, которая динамически расширяется по мере необходимости.
#Java #Training #Medium #Garbage_collector
JVM поддерживает несколько типов сборок мусора, каждый из которых предназначен для определенного типа приложений:
Serial GC:
Использует один поток для выполнения всех операций GC.
Подходит для однопоточных приложений или программ с небольшими кучами.
Parallel GC (или Throughput Collector):
Использует несколько потоков для сборки мусора.
Хорош для многопоточных приложений, стремящихся минимизировать время пауз.
CMS (Concurrent Mark-Sweep):
Предназначен для минимизации пауз при сборке мусора.
Выполняет маркировку и удаление объектов одновременно с выполнением программы.
Более ресурсоемкий и требует больше CPU.
G1 (Garbage First):
Продвинутый сборщик, ориентированный на минимизацию пауз.
Делит память на множество регионов и выполняет сборку в приоритетных областях.
ZGC и Shenandoah:
Современные сборщики мусора с низкими паузами.
Ориентированы на большие кучи и высокую производительность.
Особенности сборки мусора в разных регионах памяти
Память в JVM делится на несколько регионов, каждый из которых имеет свои особенности:
Young Generation:
Основные области: Eden, Survivor From, Survivor To.
В этой области происходят минорные сборки (Minor GC) — сборки, которые удаляют недостижимые объекты в молодом поколении.
Old Generation:
Сюда попадают объекты, которые "пережили" несколько минорных сборок.
Сборка в этой области называется Full GC или Major GC и является более затратной по времени.
Permanent Generation (Metaspace):
Содержит метаинформацию, загружаемые классы и методы.
В более новых версиях JVM (с Java 8) эта область была заменена на Metaspace, которая динамически расширяется по мере необходимости.
#Java #Training #Medium #Garbage_collector
Что выведет код?
#Tasks
import java.util.*;
public class Task141024 {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "orange"));
list.add(1, "grape");
list.set(2, "pear");
for (Iterator<String> it = list.iterator(); it.hasNext();) {
String fruit = it.next();
if (fruit.equals("pear")) {
it.remove();
}
}
System.out.println(list);
}
}
#Tasks
Варианты ответа:
Anonymous Quiz
10%
[apple, grape, orange, pear]
24%
[apple, grape, pear]
0%
[grape, pear, orange]
67%
[apple, grape, orange]
Внутреннее устройство Garbage Collector
Garbage Collector в Java работает на основе трех основных принципов:
Поиск недостижимых объектов.
Освобождение занимаемой ими памяти.
Компактизация и дефрагментация кучи (опционально, в зависимости от алгоритма).
1. Поиск недостижимых объектов
Каждый объект в Java находится в куче, и на него указывают ссылки (references). GC определяет объекты, которые больше не используются, с помощью концепции достижимости (Reachability). В JVM есть специальные точки, называемые корнями GC (GC Roots), от которых начинается проверка достижимости объектов.
Примеры GC Roots:
Локальные переменные и параметры метода.
Статические поля классов.
Ссылки из JNI (Java Native Interface).
Активные потоки.
Алгоритм маркировки и удаления (Mark and Sweep) проходит по GC Roots и помечает все объекты, до которых можно дотянуться. Недостижимые объекты (не помеченные) считаются кандидатами для удаления.
2. Освобождение памяти
После маркировки всех достижимых объектов начинается этап удаления. В зависимости от используемого GC, могут применяться разные стратегии удаления:
Сборка с переносом (Copying) — применимо в молодом поколении (Young Generation).
Удаление без компактизации — объекты удаляются, но места остаются фрагментированными.
Компактизация — память сжимается, перемещая все объекты в одну часть кучи.
3. Компактизация и дефрагментация
Когда объекты удаляются из памяти, в куче остаются «пустые» фрагменты, которые приводят к фрагментации. Некоторые GC, такие как G1 или Serial GC, выполняют компактизацию, чтобы переместить оставшиеся объекты и освободить непрерывный блок памяти. Компактизация полезна для улучшения производительности при выделении памяти новым объектам.
Виды Garbage Collector и их внутреннее устройство
Каждый сборщик мусора в JVM имеет свои особенности и алгоритмы, которые влияют на производительность и паузы приложения. Рассмотрим основные GC и их внутренние механизмы:
Serial GC:
Самый простой алгоритм, использующий однопоточную сборку мусора.
Сначала выполняет маркировку, затем удаляет недостижимые объекты и сжимает оставшиеся объекты.
Используется в основном для небольших приложений или однопоточных систем.
Parallel GC:
Многопоточная версия Serial GC.
Параллельно выполняет маркировку и удаление объектов.
Эффективно работает в многопроцессорных системах.
CMS (Concurrent Mark-Sweep):
Выполняет асинхронную сборку мусора, минимизируя паузы.
Этапы работы:
Initial Mark — быстрая маркировка активных объектов.
Concurrent Mark — параллельная маркировка всех достижимых объектов.
Concurrent Sweep — удаление недостижимых объектов.
Избегает компактизации, что может привести к фрагментации.
G1 GC (Garbage First):
Разделяет память на множество небольших регионов.
Выполняет параллельную сборку в приоритетных регионах.
Объединяет алгоритмы маркировки, удаления и сжатия.
Оптимизирован для минимизации пауз.
ZGC:
Сборщик мусора с нулевыми паузами.
Использует механизм цветной маркировки (Coloring) для управления памятью.
Работает на больших объемах памяти и в многопоточных приложениях.
Shenandoah:
Также минимизирует паузы за счет выполнения конкурентного перемещения объектов.
В отличие от ZGC, реализует дополнительные стратегии для снижения влияния на приложение.
#Java #Training #Medium #Garbage_collector
Garbage Collector в Java работает на основе трех основных принципов:
Поиск недостижимых объектов.
Освобождение занимаемой ими памяти.
Компактизация и дефрагментация кучи (опционально, в зависимости от алгоритма).
1. Поиск недостижимых объектов
Каждый объект в Java находится в куче, и на него указывают ссылки (references). GC определяет объекты, которые больше не используются, с помощью концепции достижимости (Reachability). В JVM есть специальные точки, называемые корнями GC (GC Roots), от которых начинается проверка достижимости объектов.
Примеры GC Roots:
Локальные переменные и параметры метода.
Статические поля классов.
Ссылки из JNI (Java Native Interface).
Активные потоки.
Алгоритм маркировки и удаления (Mark and Sweep) проходит по GC Roots и помечает все объекты, до которых можно дотянуться. Недостижимые объекты (не помеченные) считаются кандидатами для удаления.
2. Освобождение памяти
После маркировки всех достижимых объектов начинается этап удаления. В зависимости от используемого GC, могут применяться разные стратегии удаления:
Сборка с переносом (Copying) — применимо в молодом поколении (Young Generation).
Удаление без компактизации — объекты удаляются, но места остаются фрагментированными.
Компактизация — память сжимается, перемещая все объекты в одну часть кучи.
3. Компактизация и дефрагментация
Когда объекты удаляются из памяти, в куче остаются «пустые» фрагменты, которые приводят к фрагментации. Некоторые GC, такие как G1 или Serial GC, выполняют компактизацию, чтобы переместить оставшиеся объекты и освободить непрерывный блок памяти. Компактизация полезна для улучшения производительности при выделении памяти новым объектам.
Виды Garbage Collector и их внутреннее устройство
Каждый сборщик мусора в JVM имеет свои особенности и алгоритмы, которые влияют на производительность и паузы приложения. Рассмотрим основные GC и их внутренние механизмы:
Serial GC:
Самый простой алгоритм, использующий однопоточную сборку мусора.
Сначала выполняет маркировку, затем удаляет недостижимые объекты и сжимает оставшиеся объекты.
Используется в основном для небольших приложений или однопоточных систем.
Parallel GC:
Многопоточная версия Serial GC.
Параллельно выполняет маркировку и удаление объектов.
Эффективно работает в многопроцессорных системах.
CMS (Concurrent Mark-Sweep):
Выполняет асинхронную сборку мусора, минимизируя паузы.
Этапы работы:
Initial Mark — быстрая маркировка активных объектов.
Concurrent Mark — параллельная маркировка всех достижимых объектов.
Concurrent Sweep — удаление недостижимых объектов.
Избегает компактизации, что может привести к фрагментации.
G1 GC (Garbage First):
Разделяет память на множество небольших регионов.
Выполняет параллельную сборку в приоритетных регионах.
Объединяет алгоритмы маркировки, удаления и сжатия.
Оптимизирован для минимизации пауз.
ZGC:
Сборщик мусора с нулевыми паузами.
Использует механизм цветной маркировки (Coloring) для управления памятью.
Работает на больших объемах памяти и в многопоточных приложениях.
Shenandoah:
Также минимизирует паузы за счет выполнения конкурентного перемещения объектов.
В отличие от ZGC, реализует дополнительные стратегии для снижения влияния на приложение.
#Java #Training #Medium #Garbage_collector
Внешнее управление сборщиком мусора
JVM предоставляет множество параметров, позволяющих управлять работой GC. Основные параметры включают:
Выбор алгоритма GC:
-XX:+UseSerialGC — включает Serial GC.
-XX:+UseParallelGC — включает Parallel GC.
-XX:+UseConcMarkSweepGC — включает CMS.
-XX:+UseG1GC — включает G1 GC.
-XX:+UseZGC — включает ZGC.
Настройка размеров памяти:
-Xms<size> — начальный размер кучи.
-Xmx<size> — максимальный размер кучи.
-XX:NewSize=<size> — размер молодого поколения.
-XX:MaxNewSize=<size> — максимальный размер молодого поколения.
Параметры управления метасферой (Metaspace):
-XX:MetaspaceSize=<size> — начальный размер метасферы.
-XX:MaxMetaspaceSize=<size> — максимальный размер метасферы.
Вывод информации о работе GC:
-XX:+PrintGCDetails — выводит детализированную информацию о сборках мусора.
-Xlog:gc* — в Java 9 и выше используется для логирования событий GC.
-XX:+HeapDumpOnOutOfMemoryError — создаёт дамп памяти при ошибке OutOfMemoryError.
Примеры управления GC с параметрами JVM
Допустим, у нас есть Java-приложение с высоким потреблением памяти. Мы хотим минимизировать паузы GC и эффективно использовать ресурсы.
Запуск с G1 GC и детальным логированием:
Диагностика и мониторинг работы GC
Понимание поведения сборщика мусора требует мониторинга его работы в реальном времени. Для этого существуют различные инструменты:
JVisualVM:
Графический инструмент для мониторинга памяти, потоков и GC.
Позволяет отслеживать метрики производительности и визуализировать сборки мусора.
JConsole:
Встроенный инструмент для мониторинга JVM.
Позволяет контролировать использование памяти, сборку мусора и состояние потоков.
GC Logs:
Логирование работы GC позволяет анализировать частоту и продолжительность сборок.
Для Java 8 и выше рекомендуется использовать параметр -Xlog:gc*.
JFR (Java Flight Recorder):
Мощный инструмент профилирования, который записывает метрики производительности, использование памяти и действия GC.
Запускается с параметром -XX:StartFlightRecording.
Пример анализа логов:
Пример программы, создающей большое количество объектов, чтобы увидеть работу разных сборщиков мусора:
Запустите эту программу с разными настройками GC, чтобы увидеть, как меняется поведение:
#Java #Training #Medium #Garbage_collector
JVM предоставляет множество параметров, позволяющих управлять работой GC. Основные параметры включают:
Выбор алгоритма GC:
-XX:+UseSerialGC — включает Serial GC.
-XX:+UseParallelGC — включает Parallel GC.
-XX:+UseConcMarkSweepGC — включает CMS.
-XX:+UseG1GC — включает G1 GC.
-XX:+UseZGC — включает ZGC.
Настройка размеров памяти:
-Xms<size> — начальный размер кучи.
-Xmx<size> — максимальный размер кучи.
-XX:NewSize=<size> — размер молодого поколения.
-XX:MaxNewSize=<size> — максимальный размер молодого поколения.
Параметры управления метасферой (Metaspace):
-XX:MetaspaceSize=<size> — начальный размер метасферы.
-XX:MaxMetaspaceSize=<size> — максимальный размер метасферы.
Вывод информации о работе GC:
-XX:+PrintGCDetails — выводит детализированную информацию о сборках мусора.
-Xlog:gc* — в Java 9 и выше используется для логирования событий GC.
-XX:+HeapDumpOnOutOfMemoryError — создаёт дамп памяти при ошибке OutOfMemoryError.
Примеры управления GC с параметрами JVM
Допустим, у нас есть Java-приложение с высоким потреблением памяти. Мы хотим минимизировать паузы GC и эффективно использовать ресурсы.
Запуск с G1 GC и детальным логированием:
java -Xms2g -Xmx4g -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCTimeStamps MyApp
Этот запуск включает G1 GC, устанавливает начальный размер кучи на 2 ГБ и максимальный на 4 ГБ, а также выводит подробные логи.
Диагностика и мониторинг работы GC
Понимание поведения сборщика мусора требует мониторинга его работы в реальном времени. Для этого существуют различные инструменты:
JVisualVM:
Графический инструмент для мониторинга памяти, потоков и GC.
Позволяет отслеживать метрики производительности и визуализировать сборки мусора.
JConsole:
Встроенный инструмент для мониторинга JVM.
Позволяет контролировать использование памяти, сборку мусора и состояние потоков.
GC Logs:
Логирование работы GC позволяет анализировать частоту и продолжительность сборок.
Для Java 8 и выше рекомендуется использовать параметр -Xlog:gc*.
JFR (Java Flight Recorder):
Мощный инструмент профилирования, который записывает метрики производительности, использование памяти и действия GC.
Запускается с параметром -XX:StartFlightRecording.
Пример анализа логов:
java -Xms1g -Xmx2g -XX:+UseG1GC -Xlog:gc:gc.log -XX:+PrintGCDetails MyApp
После выполнения мы можем открыть файл gc.log и проанализировать все события, связанные с GC, например, частоту минорных и мажорных сборок, продолжительность пауз и использование памяти.
Пример программы, создающей большое количество объектов, чтобы увидеть работу разных сборщиков мусора:
public class GCExample {
public static void main(String[] args) {
for (int i = 0; i < 10_000_000; i++) {
createObjects();
}
}
private static void createObjects() {
String[] strings = new String[1000];
for (int i = 0; i < strings.length; i++) {
strings[i] = new String("Object " + i);
}
}
}
Запустите эту программу с разными настройками GC, чтобы увидеть, как меняется поведение:
java -Xms512m -Xmx1g -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCDateStamps GCExample
#Java #Training #Medium #Garbage_collector
Мусорные ссылки в Java
В Java существует механизм управления памятью, который включает использование ссылок для работы с объектами. В дополнение к обычным ссылкам на объекты, Java предоставляет особый тип ссылок, называемый мусорными ссылками (Garbage References), который позволяет более гибко управлять памятью и поведением объектов в условиях автоматической сборки мусора.
Мусорные ссылки (или гибкие ссылки) представляют собой четыре основных типа ссылок: сильные (Strong), мягкие (Soft), слабые (Weak) и фантомные (Phantom). Эти типы ссылок определяют, каким образом объекты могут быть удалены сборщиком мусора и как приложения могут использовать эту информацию для управления ресурсами.
1. Сильные ссылки (Strong References)
Сильные ссылки — это стандартный тип ссылок в Java. Они используются по умолчанию при создании объектов и препятствуют сборке мусора. Пока объект доступен через сильную ссылку, сборщик мусора никогда не удалит его из памяти.
Пример сильной ссылки:
Сильные ссылки применяются в большинстве случаев, так как они обеспечивают стандартное управление памятью в Java, но в некоторых ситуациях они могут приводить к утечкам памяти, если на объекты продолжают ссылаться даже после их использования.
2. Мягкие ссылки (Soft References)
Мягкие ссылки используются, когда объект может быть удален сборщиком мусора при нехватке памяти, но до тех пор, пока память доступна, объект продолжает оставаться в куче. Это делает их идеальными для реализации кэширования объектов. Мягкие ссылки удаляются только перед выбросом OutOfMemoryError, когда JVM пытается освободить память.
Пример использования мягкой ссылки:
#Java #Training #Medium #Garbage_References
В Java существует механизм управления памятью, который включает использование ссылок для работы с объектами. В дополнение к обычным ссылкам на объекты, Java предоставляет особый тип ссылок, называемый мусорными ссылками (Garbage References), который позволяет более гибко управлять памятью и поведением объектов в условиях автоматической сборки мусора.
Мусорные ссылки (или гибкие ссылки) представляют собой четыре основных типа ссылок: сильные (Strong), мягкие (Soft), слабые (Weak) и фантомные (Phantom). Эти типы ссылок определяют, каким образом объекты могут быть удалены сборщиком мусора и как приложения могут использовать эту информацию для управления ресурсами.
1. Сильные ссылки (Strong References)
Сильные ссылки — это стандартный тип ссылок в Java. Они используются по умолчанию при создании объектов и препятствуют сборке мусора. Пока объект доступен через сильную ссылку, сборщик мусора никогда не удалит его из памяти.
Пример сильной ссылки:
StringBuilder sb = new StringBuilder("Hello, World!");
В данном примере переменная sb ссылается на объект типа StringBuilder. Пока существует ссылка sb, объект не может быть удален сборщиком мусора, даже если больше ни одна часть программы не обращается к нему.
Сильные ссылки применяются в большинстве случаев, так как они обеспечивают стандартное управление памятью в Java, но в некоторых ситуациях они могут приводить к утечкам памяти, если на объекты продолжают ссылаться даже после их использования.
2. Мягкие ссылки (Soft References)
Мягкие ссылки используются, когда объект может быть удален сборщиком мусора при нехватке памяти, но до тех пор, пока память доступна, объект продолжает оставаться в куче. Это делает их идеальными для реализации кэширования объектов. Мягкие ссылки удаляются только перед выбросом OutOfMemoryError, когда JVM пытается освободить память.
Пример использования мягкой ссылки:
import java.lang.ref.SoftReference;
public class SoftReferenceExample {
public static void main(String[] args) {
// Создаем сильную ссылку на объект
String strongReference = new String("Hello, World!");
// Создаем мягкую ссылку на объект
SoftReference<String> softReference = new SoftReference<>(strongReference);
// Убираем сильную ссылку
strongReference = null;
// Получаем объект из мягкой ссылки
if (softReference.get() != null) {
System.out.println("Object is still in memory: " + softReference.get());
} else {
System.out.println("Object has been collected by GC.");
}
}
}
Если памяти достаточно, вывод будет: Object is still in memory: Hello, World!. Но если память заканчивается, объект будет удален, и ссылка softReference.get() вернет null.
#Java #Training #Medium #Garbage_References
3. Слабые ссылки (Weak References)
Слабые ссылки удаляются сборщиком мусора при первой же сборке мусора, если нет других сильных или мягких ссылок на объект. Этот тип ссылок полезен для реализации карточек кеширования, таких как WeakHashMap, где объекты автоматически удаляются из памяти при отсутствии других активных ссылок.
Пример использования слабой ссылки:
В большинстве случаев, если сразу после удаления сильной ссылки вызывается сборщик мусора, то вывод будет: Object has been collected by GC.
Слабые ссылки активно применяются в таких структурах, как WeakHashMap, для реализации автоматического удаления объектов, которые больше не используются.
4. Фантомные ссылки (Phantom References)
Фантомные ссылки — самый слабый тип ссылок в Java. Они используются для определения момента, когда объект уже удален из памяти, но еще не произошла его окончательная очистка. Фантомные ссылки используются для чистки ресурсов (например, освобождения файловых дескрипторов или сокетов) после того, как объект больше недоступен.
Фантомные ссылки нельзя использовать для доступа к объекту напрямую. Вместо этого они помещаются в очередь ссылок (ReferenceQueue) и ожидают обработки.
Пример использования фантомных ссылок:
Применение мусорных ссылок
Кэширование:
Мягкие ссылки позволяют эффективно управлять кэшами, автоматически удаляя данные при нехватке памяти.
Очистка ресурсов:
Фантомные ссылки применяются для очистки ресурсов, таких как файлы и потоки.
Сборка объектов:
Слабые ссылки полезны для автоматического удаления объектов из коллекций, таких как WeakHashMap, и для реализации пулов объектов.
Отслеживание состояния объектов:
Фантомные ссылки позволяют определить, когда объект окончательно удален из памяти.
#Java #Training #Medium #Garbage_References
Слабые ссылки удаляются сборщиком мусора при первой же сборке мусора, если нет других сильных или мягких ссылок на объект. Этот тип ссылок полезен для реализации карточек кеширования, таких как WeakHashMap, где объекты автоматически удаляются из памяти при отсутствии других активных ссылок.
Пример использования слабой ссылки:
import java.lang.ref.WeakReference;
public class WeakReferenceExample {
public static void main(String[] args) {
// Создаем сильную ссылку на объект
String strongReference = new String("Weak Reference Example");
// Создаем слабую ссылку на объект
WeakReference<String> weakReference = new WeakReference<>(strongReference);
// Убираем сильную ссылку
strongReference = null;
// Вызываем сборщик мусора
System.gc();
// Проверяем наличие объекта в памяти
if (weakReference.get() != null) {
System.out.println("Object is still in memory: " + weakReference.get());
} else {
System.out.println("Object has been collected by GC.");
}
}
}
В большинстве случаев, если сразу после удаления сильной ссылки вызывается сборщик мусора, то вывод будет: Object has been collected by GC.
Слабые ссылки активно применяются в таких структурах, как WeakHashMap, для реализации автоматического удаления объектов, которые больше не используются.
4. Фантомные ссылки (Phantom References)
Фантомные ссылки — самый слабый тип ссылок в Java. Они используются для определения момента, когда объект уже удален из памяти, но еще не произошла его окончательная очистка. Фантомные ссылки используются для чистки ресурсов (например, освобождения файловых дескрипторов или сокетов) после того, как объект больше недоступен.
Фантомные ссылки нельзя использовать для доступа к объекту напрямую. Вместо этого они помещаются в очередь ссылок (ReferenceQueue) и ожидают обработки.
Пример использования фантомных ссылок:
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
public class PhantomReferenceExample {
public static void main(String[] args) {
String phantomReferenceString = new String("Phantom Reference Example");
// Создаем очередь для фантомных ссылок
ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
// Создаем фантомную ссылку
PhantomReference<String> phantomReference = new PhantomReference<>(phantomReferenceString, referenceQueue);
// Удаляем сильную ссылку
phantomReferenceString = null;
// Вызываем сборщик мусора
System.gc();
// Проверяем, помещена ли фантомная ссылка в очередь
Reference<? extends String> ref = referenceQueue.poll();
if (ref != null) {
System.out.println("Object has been collected and reference is in the queue.");
} else {
System.out.println("Object is not yet collected by GC.");
}
}
}
В этом примере вывод покажет, что фантомная ссылка была добавлена в очередь после удаления объекта. Это означает, что объект был удален из памяти, и теперь его можно использовать для выполнения дополнительных действий.
Применение мусорных ссылок
Кэширование:
Мягкие ссылки позволяют эффективно управлять кэшами, автоматически удаляя данные при нехватке памяти.
Очистка ресурсов:
Фантомные ссылки применяются для очистки ресурсов, таких как файлы и потоки.
Сборка объектов:
Слабые ссылки полезны для автоматического удаления объектов из коллекций, таких как WeakHashMap, и для реализации пулов объектов.
Отслеживание состояния объектов:
Фантомные ссылки позволяют определить, когда объект окончательно удален из памяти.
#Java #Training #Medium #Garbage_References
Что выведет код?
#Tasks
public class Task151024 {
static Task151024 obj;
public static void main(String[] args) {
Task151024 m1 = new Task151024();
Task151024 m2 = new Task151024();
m1 = null;
obj = m2;
m2 = null;
System.gc();
System.out.println("Done");
}
@Override
protected void finalize() {
System.out.println("Object collected");
}
}
#Tasks
Варианты ответа:
Anonymous Quiz
41%
Done
29%
Object collected\nDone
24%
Done\nObject collected
6%
Object collected