Czarna dziura zasobów Claude Code: od 11,3 MB pojedynczego pliku do 1,2 TB pożerania dysku
Categories:
Claude Code jest aplikacją Node.js w postaci jednego pliku bez zarządzania cyklem życia zasobów: przy uruchomieniu analizuje 11,3 MB plik pakietu, w czasie działania nieograniczenie zapisuje na dysk, a po zamknięciu terminala proces nadal żyje i zużywa pamięć, aż system się zawiesi. Na podstawie rzeczywistych zgłoszeń użytkowników w GitHub Issues oraz społecznościowej analizy odwrotnej, w niniejszym artykule systematycznie omawiamy wady zarządzania zasobami w trzech wymiarach: pamięci, CPU i dysku, ujawniając strukturalne problemy w architekturze pakowania, projektowaniu przechowywania i zarządzaniu cyklem życia procesów. Nie są to przypadkowe edge case, lecz systematyczne wady architektury zgłaszane od sierpnia 2025 do kwietnia 2026, które były masowo zamykane przez bota stale.
Architektura pakowania: koszt jednego pliku 11,3 MB
Rdzeniem Claude Code jest jednoplikowy artefakt cli.js o rozmiarze około 11,3 MB. Użytkownik społecznościowy paultendo przeprowadził szczegółową analizę statyczną w Issue #29481, ujawniając liczne poważne problemy architektoniczne.
Czas uruchomienia V8: 32 % czasu na parsowanie
Profilowanie CPU wykazało, że compileSourceTextModule zużyło 31,7 % czasu próbkowania w fazie uruchamiania. Silnik V8 potrzebuje około 300 ms na parsowanie tego 11,3 MB pliku, podczas gdy czysty skrypt Node.js parsuje w 23 ms. Dodatkowe 7,3 % zużycia przypada na wywołanie spawnSync, a 3,5 % na garbage collection. Oznacza to, że przed wprowadzeniem jakiejkolwiek komendy użytkownika ponad 40 % czasu uruchamiania jest tracone na czyste koszty parsowania.
Pełne ładowanie: tylko 20 dynamicznych importów
Cały pakiet jest w pełni parsowany i wykonywany przy starcie, a w kodzie znajduje się jedynie 20 wyrażeń import(). Każdy użytkownik płaci cenę za wszystkie funkcje, niezależnie od ich użycia. Poniżej komponenty, które powinny być ładowane na żądanie, ale są w pełni pakowane:
pie title Skład pakietu (≈ 13,5 MB)
"Logika aplikacji" : 7540
"AWS Bedrock SDK" : 1100
"highlight.js (182 języki)" : 1000
"OpenTelemetry" : 900
"Google Vertex + gRPC + Protobuf" : 800
"RxJS" : 300
"Inne (Ink, Zod, Ajv, Axios itp.)" : 1807Asystent kodowania potrzebuje podświetlenia Brainfuck, MIPS assembly, Flix, Zephir, Inform7, Lasso i innych 182 języków – co samo w sobie świadczy o prymitywnej strategii pakowania. Zachowując jedynie około 40 najpopularniejszych języków, można zaoszczędzić ok. 786 KB kosztów parsowania.
Redundancja zależności: cztery klienty HTTP, trzy biblioteki walidacji
Różne SDK wprowadzają własne zależności, co skutkuje jednoczesnym obecnością czterech klientów HTTP (Axios, Undici, Got, natywny fetch) oraz trzech bibliotek walidacji (Zod, Ajv, JSON Schema). W środowisku Node 18+ natywny fetch jest w pełni dostępny i nie wymaga dodatkowych klientów.
413 synchronicznych wywołań systemu plików
Pakiet zawiera 196 wywołań existsSync, 109 statSync, 108 readFileSync, 58 mkdirSync i łącznie 413 synchronicznych operacji na systemie plików. Każde z nich blokuje pętlę zdarzeń. Wiele wywołań stosuje wzorzec existsSync(path) && readFileSync(path), który mógłby zostać zastąpiony jednym asynchronicznym try { await readFile(path) } catch {}.
1087 wrapperów CJS/ESM
Każdy moduł CommonJS włączony do ESM generuje kompatybilny shim __toESM/__commonJS/__require, łącznie 1087 sztuk. Te shim’y zwiększają wagę parsowania i wprowadzają drobny narzut czasu wykonania dla każdego modułu.
Niepotrzebny polyfill Node 20
Pakiet zawiera 62 shim’y Promise (obsługiwane natywnie od Node 0.12), 57 shim’y Symbol (od Node 4), 57 pomocniczych funkcji async (od Node 8) oraz 3 polyfill’e AbortController (od Node 15). Są to zależności pochodzące z transpilacji dla starszych wersji Node lub przeglądarek i są całkowicie zbędne w docelowym środowisku uruchomieniowym.
ripgrep – wszystkie 6 platformowych binarek: 61 MB
Wszystkie 6 binarki ripgrep dla różnych platform są pakowane, co daje łącznie 61 MB. W przeciwieństwie do tego, sharp prawidłowo korzysta z optional dependencies i instaluje tylko binarkę dla bieżącej platformy. To oznacza, że każde uruchomienie marnuje ok. 51 MB przestrzeni dyskowej.
Wydajność renderowania Ink spada wraz z długością konwersacji
Interfejs terminalowy używa Ink (React for Terminal). Analiza wykazała 6457 wywołań createElement, 578 hooków useState, ale jedynie 11 wrapperów React.memo() – co stanowi 1,9 % wszystkich komponentów. W Ink każda aktualizacja stanu wywołuje pełną koordynację wirtualnego DOM. Podczas strumieniowej odpowiedzi każdy przychodzący token wyzwala aktualizację stanu, co powoduje niepotrzebne ponowne renderowanie nie‑memoizowanych komponentów. Wraz ze wzrostem konwersacji rośnie ilość renderowanego wyjścia, a każde ponowne renderowanie wymaga diff‑owania większej części terminala. Zjawisko to jest zgodne z opisem w Issue #22265 „spowolnienie w trakcie sesji”.
Pożeranie dysku: nieograniczony wzrost od GB do TB
Problemy z dyskiem są najpoważniejszymi defektami zarządzania zasobami Claude Code i mają najszerszy zasięg oraz najgorsze konsekwencje.
Wycieki natywnych modułów .node w Windows: 20 GB tygodniowo
Issue #23095 opisuje problem, w którym natywny plik Windows (claude.exe) przy każdej sesji wypakowuje wtyczki Node.js do katalogu tymczasowego, ale nigdy ich nie usuwa. Jeden plik ma ok. 6,6 MB; użytkownik SlothKing16 zgromadził 2813 plików w ciągu 4 dni, co daje 18 GB. Użytkownik kolkov odnotował jeszcze gorszy wynik: około 20 GB tygodniowo, a intensywni użytkownicy mogą osiągać 100 GB tygodniowo. Problem jest zgłaszany od początku 2025 r., a bot stale wielokrotnie go zamykał jako duplikat.
Katalog ~/.claude: ponad 3 GB bez zarządzania
Użytkownik kolkov przeprowadził audyt maszyny używanej codziennie przez 8 miesięcy (Issue #5024):
pie title Zajętość katalogu ~/.claude (≈ 3,1 GB)
"projects/ (zapisy sesji)" : 2500
"debug/ (logi debug)" : 303
"file-history/ (migawki plików)" : 232
"history.jsonl (globalna historia)" : 10
"Inne" : 55Kluczowe liczby: największy pojedynczy plik JSONL sesji – 203 MB, największy pod‑agent JSONL – 72 MB, history.jsonl zawiera ponad 37 000 wpisów. Wszystkie dane nie są rotowane, nie są kompresowane i nie mają mechanizmów czyszczenia. Migawki w file-history/ nie są deduplikowane – ta sama edycja pliku 10 razy tworzy 10 pełnych kopii. Logi w debug/ nigdy nie są usuwane.
Pliki wyjściowe zadań w tle: pętla samoodwołująca się 1,2 TB
Issue #32282 ujawnia niewiarygodny defekt projektowy. Gdy Claude Code uruchamia wiele agentów w tle i automatycznie wykonuje polecenie bash monitorujące postęp, plik wyjściowy jest zapisywany w tym samym katalogu, który jest jednocześnie objęty globem, co tworzy nieskończoną pętlę zwrotną:
flowchart LR
A["bash: for f in tasks/*.output; tail -5 $f"] --> B["zapis do tasks/task-A.output"]
B --> C["glob dopasowuje task-A.output"]
C --> D["tail -5 odczytuje własny output"]
D --> E["dopisuje do własnego pliku"]
E --> CWiele zgłoszeń opisuje podobny problem: 1,2 TB, 460 GB, 303 GB, 235 GB, 480 GB, 36 GB. Komentatorzy tego issue zliczyli 70 powiązanych otwartych zgłoszeń, podzielonych na 15 grup; tylko dwie pierwsze grupy zgłaszają łącznie ok. 9,5 TB zużycia dysku. Prędkość zapisu sięga 425 MB/s przy ciągłym obciążeniu 18 minut, aż dysk się wyczerpie.
Kaskadowa awaria: nieodwracalny crash po zapełnieniu dysku
Issue #24207 opisuje katastrofalny łańcuch zdarzeń po wyczerpaniu przestrzeni dyskowej:
flowchart TD
A["Dysk = 0"] --> B["Niepowodzenie zapisu .claude.json"]
B --> C["Utworzenie pliku zerowej długości"]
C --> D["Odczyt jako nieprawidłowy JSON"]
D --> E["Nadpisanie wszystkich ustawień projektu"]
E --> F["Uszkodzenie tokenów OAuth/API"]
F --> G["Wymagana ponowna autoryzacja"]
G --> H["Zatrzymanie wszystkich działających agentów/sesji"]
H --> I["Brak możliwości odzyskania po zwolnieniu miejsca"]Brak ostrzeżeń, brak łagodnego degradacji, brak ścieżki przywracania. Użytkownik musi ręcznie zakończyć wszystkie procesy, zwolnić miejsce, przywrócić konfigurację i ponownie się uwierzytelnić.
Równoczesny zapis: brak blokad, transakcji, koordynacji
W katalogu ~/.claude/ jedynym plikiem blokującym jest .update.lock (5 B). Wszystkie pozostałe pliki są zapisywane bez ochrony. Gdy wiele procesów Claude Code działa jednocześnie (agenci + pod‑agenci to typowy scenariusz), nie ma żadnej koordynacji zapisu do współdzielonych plików:
| Plik | Autor zapisu | Mechanizm blokady | Znane konsekwencje |
|---|---|---|---|
sessions-index.json | każdy projekt/ sesja | brak | warunki wyścigu |
{uuid}.jsonl | sesja główna + kompresja | brak | utrata wpisów |
.claude.json | każdy proces | brak | uszkodzenie konfiguracji (8 zgłoszeń) |
file-history/* | każda edycja/zapis | brak | nieograniczony wzrost |
Na Windows sytuacja jest gorsza: obejście atomowego zapisu (zapis do .tmp i późniejsze rename()) nie działa, ponieważ rename() zwraca EPERM, gdy plik jest otwarty przez inny proces, całkowicie niszcząc atomowość.
Pamięć i CPU: od 13 GB RSS do paniki jądra
Ekstremalne zużycie pamięci w Windows
Issue #24840 opisuje przypadek w Windows, w którym RSS wynosi 13,21 GB, a przydział pamięci wirtualnej 47,17 GB, przy całkowitej pamięci maszyny 42,56 GB. Wystąpiło 3,75 mln błędów stron, co wskazuje na ciągły I/O dysku. W ciągu 347 s czasu wykonywania, czas CPU w trybie użytkownika to jedynie 35 s – około 90 % czasu spędzono na oczekiwaniu na I/O i swap, co powoduje, że inne aplikacje (np. przeglądarka Opera) przestają reagować.
Panika jądra macOS
Issue #39253 zgłasza poważniejsze skutki: na MacBooku Pro M3 Pro (18 GB RAM) uruchomienie wielu instancji Claude Code prowadzi do paniki jądra macOS. Zauważono dwa typy panik: Jetsam OOM kill (zbyt duże obciążenie pamięci powoduje zabicie krytycznego procesu watchdogd) oraz watchdog timeout (watchdogd nie zgłasza się przez ponad 90 s z powodu wyczerpania zasobów). System restartuje się bez ostrzeżenia, bez okna dialogowego i bez możliwości zapisania pracy.
Procesy sieroty: po zamknięciu terminala nadal żyją
Issue #44507 (kwiecień 2026, kilka dni temu) opisuje podstawowy brak zarządzania cyklem życia: po zamknięciu okna terminala proces Claude Code nadal działa. Jeden proces sierota zużył 35,4 GB RSS w ciągu 21 dni, a CPU było obciążone w 95,5 %. Przyczyną jest brak obsługi process.stdin.on("end") w głównym punkcie wejścia CLI oraz ponad 55 timerów setInterval (monitorowanie, telemetry, odświeżanie paska statusu itp.), które utrzymują pętlę zdarzeń Node.js przy życiu. Sterta V8 rośnie nieograniczenie, nie ma presji GC, nie ma limitu --max-old-space-size i nie ma watchdogu samowyłączającego się.
100 % CPU zamrożenie
Issue #27415 opisuje zamrożenie 100 % CPU wywołane przez TaskStop, spowodowane niekontrolowaną pętlą posix_spawn w środowisku Bun. Issue #26224 zgłasza, że przy przetwarzaniu dużej liczby podpowiedzi Claude Code może zawiesić się na 5–20 minut.
Systematyczna awaria płaskiej architektury plików
Alokacja bez czyszczenia: wzorzec architektoniczny we wszystkich issue
Członek społeczności kolkov wielokrotnie podkreślał, że wszystkie te problemy mają wspólną przyczynę:
Ten wyciek
.nodenie jest odosobnionym bugiem – jest symptomem powtarzającego się wzorca architektonicznego, w którym Claude Code alokuje zasoby i nie je czyści.
Od 2025 do 2026 roku problem ewoluował od jednego pliku .claude.json do rozproszonych plików JSONL, ale podstawowa architektura pozostała niezmieniona: płaskie pliki, brak blokad, brak transakcji, brak czyszczenia, brak kompresji.
SQLite i lokalny demon jako alternatywa
Społeczność wielokrotnie proponowała zastąpienie płaskich plików bazą SQLite. SQLite zapewnia jednoczesny odczyt + pojedynczy zapis (WAL), transakcje gwarantujące atomowość, wbudowaną kompresję, TTL i deduplikację oraz spójność międzyplatformową.
Innym pomysłem jest wprowadzenie lokalnego demona (podobnego do serwera LSP lub architektury Dockera), przez który wszystkie procesy Claude Code komunikowałyby się za pomocą IPC, zapewniając koordynację bez zmiany warstwy przechowywania.
Analiza społeczności vs bot stale
Komentarz członka społeczności gebeer trafnie podsumował sytuację:
Dziękuję za szczegółową analizę. To powinno było zostać naprawione przez utrzymujących już dawno temu.
Kolkov dodał:
Ironią jest to, że społeczność właściwie wykonuje debugowanie – odwrócona inżynieria, śledzenie ścieżek błędów, dostarczanie poprawek z fragmentami kodu – a odpowiedzią jest bot zamykający wszystko po 60 dni.
Porównanie zarządzania zasobami w podobnych narzędziach
GitHub Copilot jako rozszerzenie VS Code działa w ramach ograniczeń pamięci i cyklu życia hosta rozszerzenia; Cursor, będący fork’em VS Code, dziedziczy tę samą ramę zarządzania zasobami. Oba używają SQLite lub podobnych baz danych, co naturalnie wspiera współbieżność i transakcje. Claude Code wybrał podejście z niezależnym procesem i płaskimi plikami, ale nie wdrożył odpowiedzialności za zarządzanie zasobami – brak limitu pamięci, brak kwoty dyskowej, brak watchdogów procesu, brak eleganckiego zamykania. Jego zachowanie przypomina prototyp demonstracyjny, a nie narzędzie gotowe do produkcji.
Paradoks zdolności modelu vs jakości inżynierii
11,3 MB jednoplikowy pakiet, 413 synchronicznych wywołań systemu plików, 1087 wrapperów CJS/ESM, brak czyszczenia zasobów, brak kontroli współbieżności, brak monitoringu przestrzeni dyskowej – to nie są edge case, lecz systematyczne wady architektury. Od sierpnia 2025 (Issue #5024) do kwietnia 2026 (Issue #44507) społeczność nieustannie zgłasza te same kategorie problemów, dostarcza dogłębnych analiz i propozycji poprawek, podczas gdy wiele issue jest oznaczanych jako „not planned” lub zamykanych przez bota stale. Narzędzie AI do kodowania, którego własna jakość kodu wymaga audytu i naprawy przez społeczność, stanowi ciekawy paradoks.
Jeśli używasz Claude Code, regularnie sprawdzaj rozmiar katalogu ~/.claude, usuwaj tymczasowe pliki .node i przed zamknięciem terminala używaj Ctrl+C, aby poprawnie zakończyć proces. Jeśli dysk nagle „zniknie”, przynajmniej wiesz już, gdzie szukać przyczyny.