Skip to content

Instantly share code, notes, and snippets.

@nickname55
Created February 23, 2026 06:01
Show Gist options
  • Select an option

  • Save nickname55/889d04d98720dd44fbd01a42603ce8ac to your computer and use it in GitHub Desktop.

Select an option

Save nickname55/889d04d98720dd44fbd01a42603ce8ac to your computer and use it in GitHub Desktop.
JVM SIGSEGV crash: G1GC + Lucene mmap + tmpfs race condition
# JVM SIGSEGV Crash: G1GC + Lucene mmap + tmpfs Race Condition
## Симптомы
- JVM крашится с `SIGSEGV (0xb)` при интенсивной нагрузке (реиндексация Jira, Lucene indexing)
- Problematic frames:
- `G1CMTask::make_reference_grey()+0x11b`
- `IndexSetIterator::advance_and_next()+0x11b`
- Множество потоков крашатся одновременно (`[thread XXXX also had an error]`)
- Происходит **только на tmpfs (ramdisk)**, на обычном SSD не воспроизводится
- Чем больше CPU ядер — тем чаще крашится
## Окружение
- Jira 9.3.0 в Docker
- OpenJDK 11 (Temurin 11.0.24 и 11.0.26 — обе падают)
- G1GC (default)
- Данные на tmpfs (/mnt/ramdisk)
- Linux 6.14.0-37-generic, 24 ядра, 125 GB RAM
## Причина
Race condition между Lucene и G1 Garbage Collector:
1. **Lucene** использует memory-mapped files (`MappedByteBuffer`) для записи/чтения индексов
2. **G1GC** параллельно сканирует память через `G1CMTask::make_reference_grey()` — обход ссылок в concurrent marking phase
3. Lucene создаёт/удаляет mmap-сегменты из множества потоков одновременно
4. GC попадает на страницу памяти, которую Lucene **только что размапил** (unmap) → SIGSEGV
На tmpfs это проявляется чаще потому что:
- I/O на tmpfs в 50-100x быстрее SSD
- mmap/munmap операции завершаются практически мгновенно
- Окно гонки (race window) значительно шире при высоком параллелизме
- На SSD I/O медленнее → GC успевает увидеть актуальное состояние маппинга
## Почему больше ядер = больше крашей
- При 15 ядрах: 15 потоков Lucene + GC потоки = десятки конкурентных mmap операций
- При 4 ядрах: значительно меньше конкурентных mmap операций, GC успевает
## Workarounds
### 1. Ограничить CPU (работает)
```yaml
# docker-compose.yml
services:
jira:
cpus: 4 # ограничить до 4 ядер
```
Снижает параллелизм → снижает вероятность race condition.
### 2. Вернуть данные на SSD
Оставить MySQL на tmpfs (основной bottleneck для чтения), а Jira home (индексы Lucene) на SSD.
### 3. Отключить Compressed Oops (НЕ помогает)
```
-XX:-UseCompressedOops
```
Пробовали — не помогает, баг не в compressed oops.
### 4. Сменить GC на ZGC (не проверено)
```
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
```
ZGC использует другой механизм обхода ссылок, теоретически может не крашиться.
### 5. Обновить JDK до 19+ (несовместимо с Jira 9.3)
В JDK 19+ Lucene использует `MemorySegment` API вместо `MappedByteBuffer`.
Но Jira 9.3.0 официально поддерживает только JDK 8 и 11.
## Не причина
- ❌ Перегрев CPU (температура 31-37°C при лимите 100°C)
- ❌ OOM killer (dmesg чист)
- ❌ Нехватка RAM (90 GB свободно)
- ❌ Версия JDK 11 (11.0.24 и 11.0.26 — обе крашатся)
## Ссылки
- https://bugs.openjdk.org/browse/JDK-8293114 — JDK-8293114: G1 crash on MappedByteBuffer
- https://issues.apache.org/jira/browse/LUCENE-16091 — Lucene: use MemorySegment on JDK 19+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment