Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как хранятся данные в Java: память, структуры, сериализация
В Java данные хранятся несколькими способами в разных частях памяти и хранилищах. Это критическое знание для понимания производительности и управления ресурсами.
1. Память JVM: Stack и Heap
┌─────────────────────────────────────┐
│ STACK │
│ (Локальные переменные, ссылки) │
│ │
│ Thread 1: [int age: 30] │
│ [User ref: 0x1000] │
│ │
│ Thread 2: [String name] │
│ [List ref: 0x2000] │
└─────────────────────────────────────┘
↓ ссылка
┌─────────────────────────────────────┐
│ HEAP │
│ (Объекты, массивы) │
│ │
│ 0x1000: User {age: 30, ...} │
│ 0x2000: ArrayList [1,2,3,...] │
│ 0x3000: String "Hello" │
└─────────────────────────────────────┘
2. Примитивные типы vs. Объекты
// ПРИМИТИВНЫЕ ТИПЫ — хранятся в STACK (быстро)
int age = 30; // 4 байта в stack
long salary = 50000L; // 8 байт в stack
boolean active = true; // 1 бит в stack
double rate = 2.5; // 8 байт в stack
// ОБЪЕКТЫ — ссылка в STACK, данные в HEAP
User user = new User(); // ref в stack → объект в heap
String name = "John"; // ref в stack → String в heap
List<Integer> list = new ArrayList<>(); // ref в stack
// Размеры примитивов
byte: 1 байт (−128 до 127)
short: 2 байта (−32768 до 32767)
int: 4 байта (−2^31 до 2^31-1)
long: 8 байт (−2^63 до 2^63-1)
float: 4 байта (IEEE 754)
double: 8 байт (IEEE 754)
boolean: 1 байт (true/false, но занимает 1 байт)
char: 2 байта (Unicode символ)
3. Объекты в памяти
public class User {
private int age; // 4 байта
private String name; // 8 байт (ссылка на 64-bit JVM)
private boolean active; // 1 байт (+ 7 байт padding)
private double salary; // 8 байт
}
// Размер объекта в памяти:
// Object header: 12 байт (или 16 с padding)
// age: 4 байта
// name ref: 8 байт
// active: 1 байт (+ 7 padding)
// salary: 8 байт
// = ~48 байт (зависит от JVM)
4. String пулинг
// String хранятся в специальном String Pool (в Heap)
String s1 = "hello"; // создаёт в String Pool
String s2 = "hello"; // переиспользует из Pool
System.out.println(s1 == s2); // true (одна ссылка)
String s3 = new String("hello"); // создаёт новый объект в Heap
System.out.println(s1 == s3); // false (разные объекты)
System.out.println(s1.equals(s3)); // true (одинаковое содержимое)
// Явное добавление в пул
String s4 = s3.intern(); // теперь s4 в String Pool
System.out.println(s1 == s4); // true
5. Массивы
// Примитивные массивы
int[] numbers = new int[100]; // 400 байт (100 * 4) + header
boolean[] flags = new boolean[1000]; // 1000 байт + header
// Массивы объектов
User[] users = new User[10]; // 10 ссылок (80 байт на 64-bit) + header
// Каждый user — отдельный объект в Heap
// Многомерные массивы
int[][] matrix = new int[100][100];
// = массив из 100 ссылок на массивы из 100 int
// = рассчитанное использование памяти
6. Сборка мусора (Garbage Collection)
процесс жизни объекта в Heap:
1. ALLOCATION Создание объекта
new User() → выделение памяти в Heap
2. REACHABLE Объект доступен через ссылку
User u = new User(); → u указывает на объект
3. UNREACHABLE Нет ссылок на объект
u = null; → объект становится кандидатом на GC
4. GC Сборка мусора
System.gc(); → удаление неиспользуемых объектов
(Вызывается автоматически)
7. Сериализация данных
// СЕРИАЛИЗАЦИЯ — преобразование объекта в байты
public class User implements Serializable {
private int age;
private String name;
private static final long serialVersionUID = 1L;
}
// В файл
User user = new User(30, "John");
FileOutputStream fos = new FileOutputStream("user.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(user);
oos.close();
// Из файла
FileInputStream fis = new FileInputStream("user.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
User loaded = (User) ois.readObject();
ois.close();
8. JSON сериализация (Jackson)
import com.fasterxml.jackson.databind.ObjectMapper;
User user = new User(30, "John");
// Объект → JSON строка
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
// {"age": 30, "name": "John"}
// JSON → Объект
User restored = mapper.readValue(json, User.class);
9. Хранение в БД
// RELATIONAL (SQL)
User table:
id | name | age | salary
---+-------+-----+--------
1 | John | 30 | 50000
2 | Jane | 25 | 60000
// In Java:
String query = "SELECT * FROM users WHERE id = ?";
PreparedStatement stmt = connection.prepareStatement(query);
stmt.setInt(1, userId);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
User user = new User(
rs.getInt("id"),
rs.getString("name"),
rs.getInt("age")
);
}
// NOSQL (MongoDB)
Db.users.insertOne({
"_id": ObjectId(),
"name": "John",
"age": 30,
"salary": 50000
});
// In Java:
MongoCollection<Document> collection = db.getCollection("users");
Document doc = new Document("name", "John")
.append("age", 30);
collection.insertOne(doc);
10. Cache структуры
// HashMap — хеширование с коллизиями
Map<String, User> users = new HashMap<>();
users.put("user1", new User(30, "John"));
// Хранит: hash("user1") → [User object]
// TreeMap — отсортирован по ключам
Map<String, User> sorted = new TreeMap<>(users);
// Использует Red-Black Tree структуру
// WeakHashMap — для кэша (объекты удаляются при GC)
Map<String, User> cache = new WeakHashMap<>();
user = null; // объект удалится из WeakHashMap
11. Memory Leaks — утечки памяти
// Плохо: сохранение ссылок
private static List<byte[]> list = new ArrayList<>();
public void loadData() {
byte[] data = new byte[1000000];
list.add(data); // data никогда не удалится!
}
// Хорошо: очистка
private List<byte[]> list = new ArrayList<>(); // не static
public void cleanup() {
list.clear(); // может быть GC'd
}
// Слушатели событий
button.addClickListener(() -> doSomething());
// Нужно удалить слушателя:
button.removeClickListener(listener);
12. Оптимизация памяти
// Используй примитивы вместо Wrapper объектов
int[] array = new int[1000]; // лучше
Integer[] array = new Integer[1000]; // хуже (8 байт per int)
// Кэширование String
String s = "hello".intern(); // используй пул
// Избегай излишних копий
list.stream()
.filter(...)
.map(...)
.collect(Collectors.toList()); // создаёт новый список
// Переиспользуй объекты
for (int i = 0; i < 1000000; i++) {
User user = reuseUser; // переиспользовать
user.setAge(i);
process(user);
}
Итоги хранения данных
- Stack — примитивные типы и ссылки (быстро, удаляется при выходе из scope)
- Heap — объекты (медленнее, управляется GC)
- String Pool — оптимизация для строк
- Сериализация — преобразование в байты для файлов/сети
- БД — долговременное хранилище
- Кэши — быстрый доступ к данным
- GC — автоматическое освобождение неиспользуемой памяти