Telegram Web Link
Задача для опытных Java-разработчиков: «Призрачная утечка памяти в продакшене»

🧠 Уровень: Senior Java / JVM Internals
🎯 Цель: Найти источник утечки памяти в долгоживущем Java-сервисе и объяснить поведение GC

📍 Ситуация:

У вас есть Java-сервис (Spring Boot), который стабильно работает 5–6 часов, а потом начинает резко тормозить.
Мониторинг показывает рост heap usage почти до лимита, несмотря на регулярные GC-сборки.

Интересные факты:
- GC срабатывает часто, но не очищает больше 20–30% хипа
- Не происходит OutOfMemoryError, но приложение начинает "фризить"
- Подозрения падают на кэш, но размер кэша — ограничен (Caffeine, maxSize=5000)
- Все коллекции под контролем, слабые ссылки используются
- Нет утечек в логах, нет Thread`-leak по `jstack

🧩 Задача:

1. Где искать утечку, если GC работает, но память не освобождается?
2. Почему слабые ссылки не помогают?
3. Как поведение ClassLoader может влиять на утечку?
4. Какой инструмент использовать для анализа "живых" объектов в памяти?
5. Как бы вы реализовали периодический аудит памяти в проде без перезапуска?
6. Покажи, как сработает jmap, jcmd, MAT или VisualVM для выявления источника


💡 Подсказка:
Некоторые библиотеки (особенно с рефлексией, динамической загрузкой классов и кэшем) создают утечки через неудаляемые ссылки на ClassLoader, особенно в сочетании с ThreadLocal, ScheduledExecutorService, Class.forName, URLClassLoader.

🛠 Решение:

1. Снимаем дамп памяти:

jmap -dump:format=b,file=heap.bin <PID>

или

jcmd <PID> GC.heap_dump heap.bin


2. Анализируем в Eclipse MAT:
- Сортируем объекты по retained size
- Видим ThreadLocalMap, ClassLoader, Class → strong references остаются даже после GC
- Причина — статические поля/синглтоны держат ссылки на классы, которые не выгружаются

3. Проверяем код:
- Использовался Class.forName(...) в плагин-системе
- Загруженные классы не выгружались, т.к. на них ссылается пул потоков

4. Решения:
- Использовать WeakReference к загруженным классам
- Вызывать shutdownNow() и вручную очищать ThreadLocal.remove()
- Избегать глобальных синглтонов со ссылками на классы, загружаемые динамически

5. Профилактика:
- Включить периодический jcmd GC.class_histogram
- Встроить /heapdump endpoint для отладки в проде (под защищённым доступом)

📌 Вывод:
Даже при работающем GC утечка возможна, если в памяти удерживаются ссылки через ThreadLocal, ClassLoader, или пула потоков. Это не очевидно и не вызывает OOM, но "раздувает" хип и убивает производительность.

💬 Идеальный вопрос для собеседования на позицию Java-сеньора с уклоном в JVM-интерны.

@javatg
💡 Подключение к Minio из Java

Если вы ищете способ работать с объектным хранилищем Minio из Java, то эта статья от BlackSlate — именно то, что вам нужно! Рассмотрим ключевые моменты:

Что такое Minio?
Minio — это высокопроизводительный, S3-совместимый объектный сервер с открытым исходным кодом, который позволяет легко хранить, управлять и извлекать данные. Он отлично подходит для облачных и серверных приложений.

Основные темы статьи:

- Установка и настройка Minio:
Статья описывает, как запустить Minio сервер в локальной или облачной среде. Вы узнаете, как создать пользователя и настроить доступные ключи для подключения.

- Использование Minio Java SDK:
Для работы с Minio из Java необходимо добавить соответствующую зависимость в ваш проект. В статье приведены примеры настройки Maven/Gradle:

<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.3</version>
</dependency>


- Базовые операции с хранилищем:
Вы научитесь:
- Подключаться к Minio серверу с помощью MinioClient.
- Создавать бакеты.
- Загрузить и скачать объекты.
- Удалять объекты и бакеты.

- Пример кода:
Статья содержит подробный пример кода, демонстрирующий подключение и выполнение базовых операций:

import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.GetObjectArgs;
// Другие необходимые импорты

public class MinioExample {
public static void main(String[] args) throws Exception {
// Инициализируем клиента с URL, access key и secret key
MinioClient minioClient = MinioClient.builder()
.endpoint("http://127.0.0.1:9000")
.credentials("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY")
.build();

// Создание бакета (если ещё не создан)
boolean bucketExists = minioClient.bucketExists("my-bucket");
if (!bucketExists) {
minioClient.makeBucket("my-bucket");
}

// Загрузка файла в бакет
minioClient.putObject(
PutObjectArgs.builder()
.bucket("my-bucket")
.object("example.txt")
.stream(new FileInputStream("example.txt"), -1, 10485760)
.build()
);

// Скачивание файла из бакета
InputStream stream = minioClient.getObject(
GetObjectArgs.builder()
.bucket("my-bucket")
.object("example.txt")
.build()
);
// Далее можно считать данные из stream...
stream.close();
}
}


Почему это важно?
Подключение к Minio позволяет разработчикам создавать масштабируемые, гибкие и отказоустойчивые приложения с использованием объектного хранилища. Используя Java SDK, вы получаете простой и понятный API для интеграции с вашим сервисом.

Если вы работаете над проектом, где важны быстрые операции с данными и совместимость с AWS S3 API, то этот подход — отличное решение!

✍️ Читайте полную статью: https://https://www.blackslate.io/articles/connect-to-minio-from-java

@javatg
erid: 2W5zFH6MTbv

Канал про собеседования, алгоритмы, System Design, процессы, культуру и инженерию в FAANG/BigTech

Автор канала — разработчик с 18-летним опытом, из которых 8 лет он провёл в FAANG (3,5 года — в Amazon). Работал и жил в России, Германии, Люксембурге и Великобритании, провёл более 100 технических интервью в FAANG-компании.
На канале разбираю реальные задачи с собеседований в FAANG по алгоритмам и System Design. Рассматриваю задачи из не-FAANG компаний на Java, делая акцент на многопоточность. Делюсь опытом работы в FAANG, рассказываю о процессах, технологиях и инженерной культуре, обсуждаю особенности релокации и жизни разработчика в разных странах.

Если вам интересны эти темы, подписывайтесь: www.tg-me.com/faangmaster
🚀 Java API Tip — Integer.valueOf() и кеширование 🚀

Знаешь ли ты, что Integer.valueOf(int) не всегда создаёт новый объект?

📦 Значения в диапазоне от -128 до 127 кэшируются!
Это значит, что:


Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b); // 👉 true (один и тот же объект)


Но:


Integer x = Integer.valueOf(200);
Integer y = Integer.valueOf(200);
System.out.println(x == y); // 👉 false (два разных объекта)


🔍 Почему так?

Чтобы повысить производительность и сэкономить память, Java автоматически кеширует часто используемые значения.

🛠 Кстати, ты можешь изменить границу кеша через JVM-опцию:


-XX:AutoBoxCacheMax=512


📌 Полезно, если у тебя в системе часто используются числа вне стандартного диапазона.

#Java #Performance #JVM #DevTips

@javatg
💥 Задача: Почему эта структура «ломается» в многопоточной среде?


import java.util.*;

public class BrokenImmutable {
private final Map<String, List<String>> data;

public BrokenImmutable(Map<String, List<String>> input) {
this.data = Collections.unmodifiableMap(input);
}

public Map<String, List<String>> getData() {
return data;
}

public static void main(String[] args) {
Map<String, List<String>> base = new HashMap<>();
base.put("key", new ArrayList<>(List.of("a")));

BrokenImmutable bi = new BrokenImmutable(base);
Map<String, List<String>> d = bi.getData();

d.get("key").add("🚨");

System.out.println(bi.getData());
}
}


🔍 Разбор:
С первого взгляда кажется, что BrokenImmutable — иммутабельный класс. Мы оборачиваем Map через Collections.unmodifiableMap, и поле data — final.

Но проблема в глубине структуры.

unmodifiableMap запрещает перезапись ключей, но не делает элементы внутри truly immutable. В данном случае, значение по ключу "key" — это ArrayList, которую легко модифицировать.

💣 В main() мы получили доступ к внутреннему списку и… тихо сломали инвариант класса, добавив "🚨".

Решение:
Чтобы сделать структуру действительно иммутабельной, нужно:

Копировать и оборачивать значения внутри Map.

Сделать глубокую защиту:


public BrokenImmutable(Map<String, List<String>> input) {
Map<String, List<String>> copy = new HashMap<>();
for (Map.Entry<String, List<String>> e : input.entrySet()) {
copy.put(e.getKey(), List.copyOf(e.getValue())); // immutable list
}
this.data = Map.copyOf(copy); // immutable map
}



Теперь никто не сможет мутировать data, даже если получит на него ссылку.

🧠 Вопрос на подумать:
А что если вместо ArrayList внутри Map был бы CopyOnWriteArrayList или ImmutableList от Guava? Почему CopyOnWriteArrayList — тоже плохой выбор для truly immutable структур?

@javatg
🌉 Apache Beam — единый мост между batch- и stream-обработкой данных. Этот проект позволяет описывать pipelines всего один раз, а запускать их где угодно: от локальной машины до кластеров Spark или Flink, не переписывая код.

Проект использует один API для всех сценариев — будь то анализ исторических данных или обработка бесконечных потоков событий в реальном времени. При этом инструмент не навязывает конкретную инфраструктуру, оставляя свободу выбора движка исполнения.

🤖 GitHub

@javatg
🔥 Успех в IT = скорость + знания + окружение

Здесь ты найдёшь всё это — коротко, по делу и без воды.
Пока другие ищут, где “подглядеть решение”, ты уже используешь самые свежие инструменты!

AI: www.tg-me.com/ai_machinelearning_big_data
Python: www.tg-me.com/pythonl
Linux: www.tg-me.com/linuxacademiya
Собеседования DS: www.tg-me.com/machinelearning_interview
C++ www.tg-me.com/cpluspluc
Docker: www.tg-me.com/DevopsDocker
Хакинг: www.tg-me.com/linuxkalii
Devops: www.tg-me.com/DevOPSitsec
Data Science: www.tg-me.com/data_analysis_ml
Javascript: www.tg-me.com/javascriptv
C#: www.tg-me.com/csharp_ci
Java: www.tg-me.com/java_library
Базы данных: www.tg-me.com/sqlhub
Python собеседования: www.tg-me.com/python_job_interview
Мобильная разработка: www.tg-me.com/mobdevelop
Golang: www.tg-me.com/Golang_google
React: www.tg-me.com/react_tg
Rust: www.tg-me.com/rust_code
ИИ: www.tg-me.com/vistehno
PHP: www.tg-me.com/phpshka
Android: www.tg-me.com/android_its
Frontend: www.tg-me.com/front
Big Data: www.tg-me.com/bigdatai
МАТЕМАТИКА: www.tg-me.com/data_math
Kubernets: www.tg-me.com/kubernetc
Разработка игр: https://www.tg-me.com/gamedev
Haskell: www.tg-me.com/haskell_tg
Физика: www.tg-me.com/fizmat

💼 Папка с вакансиями: www.tg-me.com/addlist/_zyy_jQ_QUsyM2Vi
Папка Go разработчика: www.tg-me.com/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: www.tg-me.com/addlist/eEPya-HF6mkxMGIy
Папка ML: https://www.tg-me.com/addlist/2Ls-snqEeytkMDgy
Папка FRONTEND: https://www.tg-me.com/addlist/mzMMG3RPZhY2M2Iy

😆ИТ-Мемы: www.tg-me.com/memes_prog
🇬🇧Английский: www.tg-me.com/english_forprogrammers
🧠ИИ: www.tg-me.com/vistehno

🎓954ГБ ОПЕНСОРС КУРСОВ: @courses
📕Ит-книги бесплатно: https://www.tg-me.com/addlist/BkskQciUW_FhNjEy

Подпишись, если хочешь быть в числе тех, кого зовут в топовые проекты!
💫 Geb — Groovy-фреймворк для автоматизации браузеров. Этот фреймворк сочетает мощь WebDriver с jQuery-подобным синтаксисом выборки элементов на Groovy, делая код для скрапинга или UI-тестов неожиданно лаконичным.

Особенность инструмента в встроенной поддержке асинхронных операций. Конструкции вроде waitFor { $("p.status").text() == "Done" } избавляют от ручного ожидания AJAX-запросов. А интеграция со Spock и JUnit позволяет использовать его как для адхок-скриптов, так и для полноценных acceptance-тестов.

🤖 GitHub

@javatg
🖥 Как разработать собственного AI-ассистента на Java? Подробный разбор на практике!

Автор показывает, как с нуля создать полноценного ассистента на Java, используя современные AI-технологии. В статье — не только теория, но и конкретные примеры кода, архитектурные решения и нюансы интеграции.

Что внутри:
● Выбор архитектуры и подготовка проекта на Spring Boot
● Интеграция с языковыми моделями (LLM) через OpenAI API
● Построение цепочек prompt-инжиниринга для гибких диалогов
● Хранение истории общения, работа с сессиями
● Создание простого web-интерфейса для управления ассистентом
● Советы по деплою, безопасности и масштабированию
● Возможность добавлять новые навыки и источники знаний

Статья идеально подойдёт, если вы хотите:
— разобраться, как работает интеграция Java-приложения с LLM
— реализовать кастомные диалоги и навыки
— быстро собрать своего AI-ассистента для бизнеса или личных задач

Ссылка на подробный гайд:
🔗 https://dmitrykornilov.net/2025/05/16/building-ai-assistant-application-in-java/

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🔧 Rundeck — open-source платформа для автоматизации рутинных операционных задач. Этот инструмент помогает стандартизировать и выполнять workflows через веб-интерфейс, CLI или API, упрощая управление инфраструктурой и развертывание скриптов на множестве узлов.

Проект разрабатывается PagerDuty и предлагает готовые решения для DevOps-инженеров и SRE. С его помощью можно организовать централизованное выполнение задач, начиная от простых скриптов до сложных многошаговых процедур с контролем доступа и логированием. Для развертывания доступны варианты с Docker, DEB/RPM-пакетами или WAR-архивом.

🤖 GitHub

@javatg
📜 JBake — генератор статических сайтов для Java-разработчиков. Этот инструмент превращает Markdown, AsciiDoc или HTML-файлы в готовые статические сайты, сохраняя при этом гибкость шаблонов через Freemarker и Groovy.

Сборка через Gradle позволяет кастомизировать процесс, а встроенная поддержка Docker избавляет от необходимости настраивать окружение вручную. Для блогов разработчиков есть удобная организация контента по датам и тегам. Проект развивается с 2013 года и сохраняет минималистичный подход — никаких избыточных зависимостей, только ядро и плагины для расширения функциональности.

🤖 GitHub

@javatg
🧠 Хитрая Java-задача: «Клонируемый итератор с разделяемым буфером»
Уровень: 💥 продвинутый (Java 17+)

🎯 Задача

Реализуйте класс CloneableIterator<T>, который:

Оборачивает любой Iterator<T>
Позволяет создать независимые клоны, каждый из которых продолжает чтение с текущего места
Поддерживает *эффективное* разделение буфера: память O(k), где k — число активных клонов
Не дублирует данные, не загружает всё в память и работает потокобезопасно (не обязательно synchronized, но без багов)

📌 Пример


CloneableIterator<Integer> base = new CloneableIterator<>(List.of(10, 20, 30, 40).iterator());

Iterator<Integer> it1 = base.clone();
Iterator<Integer> it2 = base.clone();

System.out.println(it1.next()); // 10
System.out.println(it1.next()); // 20
System.out.println(it2.next()); // 10
System.out.println(it2.next()); // 20
System.out.println(it2.next()); // 30


💡 Ограничения

• Нельзя просто скопировать Iterator или заранее собирать весь список
• Память должна освобождаться, если часть буфера уже не нужна (все клоны её прошли)
• Только стандартная библиотека Java (можно использовать Deque, ArrayList, WeakReference, Optional, AtomicInteger и т.д.)

🔍 Подсказка по архитектуре

• Ведите общий буфер типа Deque<T>
• Каждому клону сопоставляется индекс, отслеживающий позицию в буфере
• По мере продвижения всех клонов — чистим буфер до минимального индекса
• Продумайте синхронизацию доступа, если хотите потокобезопасную версию

Прототип реализации (без потокобезопасности)



import java.util.*;

public class CloneableIterator<T> {
private final Iterator<T> source;
private final List<T> buffer = new ArrayList<>();
private final List<Integer> positions = new ArrayList<>();

public CloneableIterator(Iterator<T> source) {
this.source = source;
}

public Iterator<T> clone() {
int index = 0;
positions.add(index);
int myId = positions.size() - 1;

return new Iterator<T>() {
private int pos = positions.get(myId);

@Override
public boolean hasNext() {
fillBuffer();
return pos < buffer.size();
}

@Override
public T next() {
fillBuffer();
if (pos >= buffer.size()) {
throw new NoSuchElementException();
}
T value = buffer.get(pos++);
positions.set(myId, pos);
cleanupBuffer();
return value;
}

private void fillBuffer() {
if (!source.hasNext()) return;
while (buffer.size() <= pos && source.hasNext()) {
buffer.add(source.next());
}
}

private void cleanupBuffer() {
int min = Collections.min(positions);
if (min > 0) {
buffer.subList(0, min).clear();
for (int i = 0; i < positions.size(); i++) {
positions.set(i, positions.get(i) - min);
}
}
}
};
}
}


🚀 Что можно улучшить

• Потокобезопасность (ConcurrentLinkedDeque, AtomicInteger)
• Освобождение ресурсов при уничтожении клонов (WeakReference)
• Поддержка remove()
• Версия Stream<T> с spliterator() или flatMap()

@javatg
Media is too big
VIEW IN TELEGRAM
🖥Java 25 и JEP 470: нативная работа с PEM-файлами

🚀 Что нового
• Встроенный API для разбора и генерации PEM-текста (Privacy-Enhanced Mail)
• Поддержка публичных и приватных ключей, X.509-сертификатов, CRL
• Единый высокоуровневый интерфейс без сторонних зависимостей

🔍 Почему это важно
• Упрощает интеграцию с PKI и системами безопасности
• Исключает ручной парсинг Base64 и ошибки форматирования
• Обеспечивает безопасное хранение шифруемых ключей

Video: https://www.youtube.com/watch?v=hqvMn2SwKiI
JEP 470: https://openjdk.org/jeps/470
JDK 25 EA: https://jdk.java.net/25/

#Java #OpenJDK #Security

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🚀 Jooby — лаконичный веб-фреймворк для Java и Kotlin. Этот проект предлагает минималистичный подход к созданию API — без лишних абстракций, но с поддержкой популярных серверов вроде Jetty и Netty. Инструмент универсален: один и тот же код работает как в традиционных Java-приложениях, так и в Kotlin-проектах.

Фреймворк сохраняет совместимость с существующими решениями, позволяя подключать модули для GraphQL, WebSocket или авторизации. При этом стартовый шаблон умещается в несколько строк — достаточно вызвать runApp и описать роуты.

🤖 GitHub

@javatg
Java-задача: что выведет этот код с `Integer` и `==`?


public class Main {
public static void main(String[] args) {
Integer a = 100;
Integer b = 100;
Integer x = 1000;
Integer y = 1000;

System.out.println(a == b);
System.out.println(x == y);
}
}


🔍 Варианты:
• a) true, true
• b) false, false
• c) true, false
• d) false, true

💡 Разбор:

В Java объект Integer в диапазоне от -128 до 127 кешируется. Это значит:

-
Integer a = 100; и Integer b = 100; будут ссылаться на один и тот же объект
-
Integer x = 1000; и Integer y = 1000;разные объекты, хоть и равны по значению

А оператор
== проверяет ссылочное равенство, а не значение.

Правильный ответ: c) `true`, `false`

📌 Чтобы сравнивать значения
Integer, всегда используй .equals():


System.out.println(x.equals(y)); // true


🧠 Вывод: кеш
Integer работает в пределах -128..127. За пределами — создаются новые объекты. Используй equals() вместо ==, если важны значения, а не ссылки.
📚 Spring AI Alibaba — универсальный фреймворк для создания AI-агентов. Этот проект от Alibaba предлагает необычный подход к созданию чат-ботов. Вместо простых диалоговых систем здесь можно строить сложные мультиагентные workflows с визуальным графом выполнения, интеграцией с облачными сервисами Aliyun и даже human-in-the-loop взаимодействием.

Интересно выглядит DeepResearch — агент для аналитики, умеющий самостоятельно искать информацию, обрабатывать данные и генерировать отчеты. Поддержка Nacos и OpenTelemetry делает проект готовым к продакшену из коробки.

🤖 GitHub

@javatg
🌊 Project Nessie — транзакционный каталог для data lakes с Git-подобным управлением версиями. Этот инструмент позволяет работать с данными как с кодом: создавать ветки, сливать изменения и откатывать их до предыдущих состояний. Особенно удобен для команд, которые хотят внести контроль версий в свои процессы обработки данных.

Инструмент поддерживает таблицы и представления Iceberg, а также интеграцию с популярными инструментами вроде Spark, Hive и Flink. Для быстрого старта можно развернуть готовый Docker-образ или воспользоваться CLI. Проект активно развивается: есть веб-интерфейс, аутентификация через OpenID Connect и подробная документация.

🤖 GitHub

@javatg
Forwarded from Machinelearning
This media is not supported in your browser
VIEW IN TELEGRAM
🖥 Теперь официально Google выпустили Gemini CLI - AI-агента для работы в терминале

• Лёгкий и мощный инструмент для разработки в командной строке
• Работает на базе Gemini 2.5 Pro
• Код агента в открытом доступе (Apache 2.0)
• Поддержка контекста в 1 миллион токенов
• Бесплатный тариф: до 60 запросов в минуту и 1000 в день
Привязка к Google Search
• Поддержка MCP
• Интеграция с VS Code (Gemini Code Assist)

Запуск в cli: npx https://github.com/google-gemini/gemini-cli

🔜 Анонс: https://blog.google/technology/developers/introducing-gemini-cli-open-source-ai-agent/
🔜 Github: https://github.com/google-gemini/gemini-cli/

@ai_machinelearning_big_data

#AI #ML #agent #Google
Please open Telegram to view this post
VIEW IN TELEGRAM
⛓️ Jimmer — революционный ORM для JVM (Java/Kotlin), переосмысливающий работу с данными. Этот инструмент позволяет оперировать не отдельными сущностями, а целыми графами объектов любой сложности, как при чтении, так и при сохранении.

Инструмент имеет встроенную поддержку DTO с кодогенерацией, самостоятельного устранения проблемы N+1 запросов и работы с рекурсивными структурами. ORM автоматически оптимизирует SQL-запросы, убирает лишние JOIN'ы и поддерживает многоуровневое кеширование. Проект предлагает удобные DSL для запросов, интеграцию с GraphQL и работает через APT/KSP, что обеспечивает безопасность типов на этапе компиляции.

🤖 GitHub

@androidits
💻 RSocket — протокол для реактивного взаимодействия между сервисами через TCP, WebSockets и Aeron. В отличие от традиционных HTTP-запросов, он поддерживает четыре модели обмена сообщениями: запрос-ответ, поток данных, fire-and-forget и бесконечные подписки на события.

Проект обладает zero-copy режимом для снижения задержек и Java-реализацией с интеграцией в Reactor. Подходит для микросервисов, где важны двунаправленная связь и эффективная работа с потоками данных.

🤖 GitHub

@javatg
2025/07/01 03:18:45
Back to Top
HTML Embed Code: