Il buco nero delle risorse di Claude Code: da un pacchetto singolo di 11,3 MB a un consumo di disco di 1,2 TB
Categories:
Claude Code è un’applicazione client Node.js a file singolo priva di gestione del ciclo di vita delle risorse: all’avvio analizza un pacchetto da 11,3 MB, scrive sul disco senza limiti durante l’esecuzione e, una volta chiusa la console, il processo continua a vivere consumando memoria fino al crash del sistema. Basandosi su segnalazioni reali degli utenti su GitHub Issues e analisi inversa della community, questo articolo esamina sistematicamente i difetti di gestione delle risorse in memoria, CPU e disco, rivelando problemi strutturali nell’architettura di packaging, nel design di archiviazione e nella gestione del ciclo di vita dei processi. Non si tratta di casi limite, ma di difetti architetturali sistematici segnalati dalla community da agosto 2025 a aprile 2026, spesso chiusi in massa da robot stale.
Architettura del pacchetto: il costo di un file singolo da 11,3 MB
Il nucleo di Claude Code è un unico file cli.js di circa 11,3 MB. L’utente della community paultendo ha effettuato un’analisi statica dettagliata in Issue #29481, rivelando numerosi problemi architetturali gravi.
Tempo di avvio V8: il 32 % del tempo speso per l’analisi
Il profiling CPU mostra che compileSourceTextModule ha consumato il 31,7 % del tempo di campionamento nella fase di avvio. Il motore V8 impiega circa 300 ms per analizzare questo file singolo da 11,3 MB, mentre uno script Node.js “nudo” richiede solo 23 ms. Un ulteriore 7,3 % è speso in chiamate spawnSync e il 3,5 % in garbage collection. Ciò significa che, prima che l’utente inserisca qualsiasi comando, oltre il 40 % del tempo di avvio è sprecato in pura analisi.
Caricamento completo: solo 20 import dinamici
L’intero pacchetto viene analizzato ed eseguito completamente all’avvio, con sole 20 espressioni import(). Ogni utente paga il prezzo di tutti i componenti, indipendentemente dall’uso. Di seguito i componenti che dovrebbero essere caricati on‑demand ma sono inclusi nel pacchetto completo:
pie title Composizione del pacchetto (≈ 13,5 MB)
"Logica centrale dell'applicazione" : 7540
"SDK AWS Bedrock" : 1100
"highlight.js (182 linguaggi)" : 1000
"OpenTelemetry" : 900
"Google Vertex + gRPC + Protobuf" : 800
"RxJS" : 300
"Altro (Ink, Zod, Ajv, Axios, ecc.)" : 1807Un assistente di codifica che supporta Brainfuck, MIPS assembly, Flix, Zephir, Inform7, Lasso e altri 182 linguaggi dimostra quanto sia grossolana la strategia di packaging. Limitandosi a circa 40 linguaggi comuni si risparmierebbero circa 786 KB di analisi.
Dipendenze ridondanti: quattro client HTTP, tre librerie di validazione
SDK diversi introducono dipendenze indipendenti, portando a quattro client HTTP (Axios, Undici, Got, fetch nativo) e tre librerie di validazione (Zod, Ajv, JSON Schema) nello stesso pacchetto. In ambienti Node 18+, fetch è già disponibile nativamente, rendendo superflui gli altri client.
413 chiamate sincrone al file system
Il pacchetto contiene 196 existsSync, 109 statSync, 108 readFileSync, 58 mkdirSync e così via, per un totale di 413 chiamate sincrone al file system. Ognuna blocca il loop degli eventi. Molte seguono il modello existsSync(path) && readFileSync(path), che potrebbe essere sostituito da un singolo try { await readFile(path) } catch {}.
1087 wrapper di interoperabilità CJS/ESM
Ogni modulo CommonJS incluso in ESM genera un wrapper __toESM/__commonJS/__require, per un totale di 1087. Questi wrapper aumentano il peso dell’analisi e introducono un piccolo overhead di runtime per ogni modulo.
Polyfill non necessari per Node 20
Il pacchetto contiene 62 polyfill per Promise (nativi da Node 0.12), 57 per Symbol (nativi da Node 4), 57 helper per async (nativi da Node 8) e 3 polyfill per AbortController (nativi da Node 15). Queste dipendenze provengono da transitive dependencies compilate per versioni più vecchie di Node o per browser, risultando totalmente superflue nel runtime target.
ripgrep include tutti e 6 i binari di piattaforma: 61 MB
Tutti i binari di ripgrep per 6 piattaforme sono inclusi, per un totale di 61 MB. Al contrario, sharp utilizza optional dependencies e installa solo il binario della piattaforma corrente. Questo comporta uno spreco di circa 51 MB di spazio disco per ogni installazione.
Degrado delle prestazioni di Ink con l’aumento della lunghezza della conversazione
L’interfaccia terminale usa Ink (React for Terminal). L’analisi mostra 6457 chiamate a createElement, 578 hook useState, ma solo 11 wrapper React.memo() (1,9 %). In Ink, ogni aggiornamento di stato attiva una completa riconciliazione del virtual DOM. Durante lo streaming, ogni token ricevuto genera un aggiornamento di stato, facendo ricomparire componenti non memoizzati. Con l’aumento della conversazione, l’output di rendering cresce e ogni ricomposizione richiede più diff del contenuto terminale. Questo corrisponde al fenomeno “la sessione diventa sempre più lenta” segnalato in Issue #22265.
Consumazione del disco: crescita illimitata da GB a TB
Il problema del disco è il difetto di gestione delle risorse più grave di Claude Code, con la più ampia portata e le conseguenze più critiche.
Perdita del modulo nativo .node su Windows: 20 GB a settimana
Issue #23095 descrive un problema non risolto da mesi: il binario nativo Windows (claude.exe) estrae plugin Node.js nella cartella temporanea ad ogni sessione, ma non li pulisce. Ogni file è circa 6,6 MB; l’utente SlothKing16 ha accumulato 2813 file in 4 giorni (≈ 18 GB). L’utente kolkov ha registrato circa 20 GB/settimana, con utenti pesanti che arrivano a 100 GB/settimana. Il problema è stato segnalato da inizio 2025, ma è stato chiuso più volte da robot.
Cartella ~/.claude: più di 3 GB senza gestione
L’utente kolkov ha auditato una macchina usata quotidianamente per 8 mesi in Issue #5024:
pie title Utilizzo della cartella ~/.claude (≈ 3,1 GB)
"projects/ (storico sessioni)" : 2500
"debug/ (log di debug)" : 303
"file-history/ (snapshot dei file)" : 232
"history.jsonl (storico globale)" : 10
"Altro" : 55Numero chiave: file JSONL di sessione singola fino a 203 MB, file JSONL di sotto‑agente fino a 72 MB, history.jsonl con oltre 37 000 voci. Nessuna rotazione, compressione o pulizia. Gli snapshot in file-history/ non sono deduplicati: 10 versioni complete per ogni modifica. I log in debug/ non vengono mai rimossi.
Output dei task in background: ciclo di auto‑referenza da 1,2 TB
Issue #32282 ha scoperto un difetto di design incredibile. Quando Claude Code avvia più agenti in background e lancia automaticamente un comando bash per monitorare i progressi, l’output del comando viene scritto nella stessa directory corrispondente al glob, creando un ciclo di feedback infinito:
flowchart LR
A["bash: for f in tasks/*.output; tail -5 $f"] --> B["output scritto in tasks/task-A.output"]
B --> C["glob corrisponde a task-A.output stesso"]
C --> D["tail -5 legge il proprio output"]
D --> E["append al proprio output"]
E --> CDiversi utenti hanno segnalato lo stesso problema: 1,2 TB, 460 GB, 303 GB, 235 GB, 480 GB, 36 GB. Il commentatore dell’issue ha contato 70 issue correlate, raggruppate in 15 set, con le prime due gruppi che hanno consumato circa 9,5 TB. La velocità di scrittura può raggiungere 425 MB/s per 18 minuti, fino all’esaurimento del disco.
Guasto a cascata: crash irreversibile dopo il riempimento del disco
Issue #24207 descrive la catena di eventi catastrofica quando il disco si riempie:
flowchart TD
A["Spazio disco = 0"] --> B["scrittura .claude.json fallita"]
B --> C["creazione file di lunghezza zero"]
C --> D["lettura come JSON non valido"]
D --> E["sovrascrittura di tutte le impostazioni del progetto"]
E --> F["token OAuth/API corrotti"]
F --> G["necessità di ri‑autenticazione"]
G --> H["tutti gli agenti/sessioni in esecuzione si fermano"]
H --> I["impossibile recuperare anche liberando spazio"]Nessun avviso, nessun degrado elegante, nessun percorso di recupero. L’utente deve terminare manualmente tutti i processi, liberare spazio, ripristinare configurazioni e ri‑autenticarsi.
Scritture concorrenti: nessun lock, nessuna transazione, nessuna coordinazione
Nella cartella ~/.claude/ l’unico file di lock è .update.lock (5 byte). Tutti gli altri file vengono scritti senza protezione. Quando più processi Claude Code (agente + sotto‑agente) operano simultaneamente, non c’è alcuna coordinazione:
| File | Scrittore | Meccanismo di lock | Conseguenze note |
|---|---|---|---|
sessions-index.json | ogni sessione del progetto | nessuno | condizioni di gara |
{uuid}.jsonl | sessione principale + compressione | nessuno | perdita di voci |
.claude.json | ogni processo | nessuno | configurazione corrotta (8 segnalazioni) |
file-history/* | ogni Edit/Write | nessuno | crescita illimitata |
Su Windows la situazione è peggiore: le soluzioni di scrittura atomica (scrivi .tmp poi rename()) falliscono perché rename() restituisce EPERM se il file è bloccato da un altro processo, annullando l’atomicità.
Memoria e CPU: da 13 GB RSS a panic del kernel
Consumo estremo di memoria su Windows
Issue #24840 riporta un caso estremo su Windows: RSS 13,21 GB, commit di memoria virtuale 47,17 GB, su una macchina con 42,56 GB di RAM totale. 3,75 milioni di page fault, indicando I/O disco continuo. In 347 s di esecuzione, il tempo CPU in user space è stato solo 35 s (≈ 90 % del tempo speso in attesa di I/O e swap). Questo ha reso inutilizzabili altre applicazioni (es. Opera).
Panic del kernel su macOS
Issue #39253 descrive conseguenze più gravi: su un MacBook Pro M3 Pro (18 GB RAM), più istanze di Claude Code provocano panic del kernel macOS. Sono stati osservati due tipi di panic: Jetsam OOM kill (memoria esaurita, il watchdogd viene terminato) e watchdog timeout (watchdogd non segnala per > 90 s). Il sistema si riavvia senza avvisi, senza dialoghi di errore, senza possibilità di salvare il lavoro.
Processi orfani: continuano a vivere dopo la chiusura della console
Issue #44507 (aprile 2026, pochi giorni fa) segnala una mancanza basilare di gestione del ciclo di vita: chiudendo la console, il processo Claude Code rimane attivo. Un processo isolato ha consumato 35,4 GB RSS in 21 giorni, con CPU al 95,5 %. La causa è l’assenza di un handler process.stdin.on("end") nel punto di ingresso CLI, mentre più di 55 setInterval (polling, telemetria, aggiornamento barra di stato, ecc.) mantengono vivo il loop degli eventi di Node.js. L’heap V8 cresce senza limiti, senza pressione GC, senza --max-old-space-size, senza watchdog di auto‑terminazione.
Freeze al 100 % CPU
Issue #27415 riporta un freeze al 100 % CPU scatenato da TaskStop, dovuto a un loop incontrollato di posix_spawn nel runtime Bun. Issue #26224 segnala blocchi di 5‑20 minuti quando Claude Code elabora prompt di grandi dimensioni.
Fallimento sistemico di un’architettura a file piatti
Allocazione senza pulizia: un pattern architetturale ricorrente
Il membro della community kolkov ha sottolineato più volte che tutti questi problemi condividono la stessa radice:
Questa perdita di
.nodenon è un bug isolato – è il sintomo di un pattern architetturale ricorrente, ovvero Claude Code assegna risorse senza pulirle.
Dal 2025 al 2026, il problema è passato da un singolo file .claude.json a una proliferazione di file JSONL, ma l’architettura di base è rimasta invariata: file piatti, nessun lock, nessuna transazione, nessuna pulizia, nessuna compressione.
SQLite e demone locale: soluzioni proposte dalla community
La community ha più volte suggerito di sostituire lo storage a file piatti con SQLite. Un database SQLite può risolvere tutti i problemi: modalità WAL per letture concorrenti + scrittura atomica, transazioni per garantire atomicità completa, compressione integrata, TTL per pulizia, deduplication, coerenza cross‑platform.
Un’altra proposta è introdurre un demone locale (simile a un server LSP o all’architettura Docker), con tutti i processi Claude Code che comunicano via IPC, fornendo coordinazione senza cambiare il backend di storage.
Analisi inversa della community vs robot stale
Il commento di gebeer sintetizza la situazione:
Grazie per l’analisi dettagliata. Questo avrebbero dovuto fare i manutentori molto tempo fa.
kolkov aggiunge:
Ironico è che la community faccia il debugging per loro – reverse‑engineering, tracciamento dei percorsi di errore, proposte di patch con codice – mentre il robot stale chiude tutto dopo 60 giorni.
Confronto con la gestione delle risorse di strumenti simili
GitHub Copilot, come estensione VS Code, è soggetto ai limiti di memoria e al ciclo di vita dell’host dell’estensione; Cursor, un fork di VS Code, eredita lo stesso framework di gestione delle risorse. Entrambi usano SQLite o database simili, supportando nativamente concorrenza e transazioni. Claude Code ha scelto processi indipendenti + file piatti, ma non ha implementato le responsabilità di gestione delle risorse: nessun limite di memoria, nessuna quota disco, nessun watchdog di processo, nessun shutdown elegante. Il suo comportamento è più simile a una demo prototipo che a uno strumento pronto per la produzione.
Paradosso tra capacità del modello e qualità ingegneristica
Un file singolo da 11,3 MB, 413 chiamate sincrone al file system, 1087 wrapper CJS/ESM, nessuna pulizia delle risorse, nessun controllo di concorrenza, nessun monitoraggio dello spazio disco – questi non sono casi limite, ma difetti architetturali sistematici. Da Issue #5024 (agosto 2025) a Issue #44507 (aprile 2026), la community ha costantemente segnalato la stessa categoria di problemi, fornendo analisi dettagliate e proposte di correzione, mentre molti issue sono stati etichettati “not planned” o chiusi automaticamente da robot stale. Un tool di codifica AI la cui qualità del codice richiede audit e correzioni dalla community è, di per sé, un paradosso degno di riflessione.
Se utilizzi Claude Code, controlla regolarmente la dimensione della cartella ~/.claude, rimuovi i file .node temporanei e assicurati di uscire correttamente con Ctrl + C prima di chiudere la console. Se lo spazio disco scompare improvvisamente, ora sai dove cercare la causa.