Inquirer EntertainmentJulia Montes opens up about challenges of being a CEO, executive producerESPNU.S. senators call on NBA to reevaluate Rwanda partnershipESPN Deportes¿Puede Messi ganar su noveno Balón de Oro a los 39 años?The Jerusalem PostPutin to meet Iran's Pezeshkian, Emir of Qatar on Tuesday in Moscow, Kremlin saysDaily MaverickEl Niño threatens to deepen southern Africa’s poverty crisis7sur7Sans leader ni expérience politique, un mouvement étudiant prend le pouvoir en Serbie: comment est-ce possible?NumeramaUn laser anti-drone testé sur le Charles de Gaulle en juin, une première pour un porte-avions françaisEuronewsUK: Oxford Street pedestrianisation begins in central LondonLa PresseContestation de la décision judiciaire dans Vachon | La candidate libérale défaite invoque le respect du droit de vote de chaque citoyenCBS NewsMaurene Comey, James Comey's daughter, was unlawfully fired, judge rulesDigital SpyEastEnders confirms five major absences for Zoe Slater's funeral this weekMeduzaАйтишнику Юрию Беленькому дали 13 лет по делу о донатах ВСУ. Его данные российским силовикам выдала криптобиржа Binance
The Daily Newsstand · Free, Always
Monday, October 26, 2026

Пятнадцать сессий Claude Code съели 11 ГБ памяти. Я написал мод, который показывает, кто именно

Translate

Обычно у меня открыто десять-пятнадцать сессий Claude Code. Одна чинит тесты в одном репозитории, другая пилит фронтенд в соседнем worktree, третья с утра ждёт моего ответа, а про четвёртую я честно забыл. У каждой свои субагенты и MCP-серверы, где-то поднят vite, где-то крутится pytest. Какое-то время это работало, а потом 64-гигабайтная машина начала задумываться над каждым переключением окна.

Я открыл диспетчер задач и увидел то, что наверняка видел каждый, кто так работает: стену одинаковых node и claude. Сколько они едят, видно. Чьи они, не видно совсем. Можно было закрыть пару окон наугад и надеяться, что попал в нужное, но надеяться в таком деле не хотелось.

Так появился claude-load, мод для Claude Code, который раскладывает нагрузку машины по сессиям. Первый же запуск показал 15 живых сессий, которые вместе держали 10,8 ГБ. Большинство давно простаивали со смёрженными PR, а одна гоняла забытый Python, хотя родителя у него уже не было.

Чей это node?

Имя процесса тут бесполезно: у всех сессий одни и те же claude, node и bash. Зато Claude Code сам ведёт реестр живых сессий. В ~/.claude/sessions/ на каждую лежит файл <pid>.json, и в нём есть почти всё, что нужно:

{
  "pid": 18636,
  "sessionId": "a3a4722e-…",
  "name": "Refactor the auth middleware",
  "status": "busy",
  "cwd": "C:\\work\\api",
  "entrypoint": "claude-desktop"
}

Формат нигде не описан, так что мод берёт из файла только эти поля и спокойно переживает момент, когда Claude его перезаписывает. Рядом лежат файлы *.key с токенами, их мод не открывает вообще.

Остальное — обход дерева. Сэмплер получает список всех процессов с родителями и от каждого поднимается по цепочке PPID, пока не упрётся в PID какой-нибудь сессии. Всё, что под ней, и есть её нагрузка. Пройденные цепочки запоминаются, поэтому даже сотни процессов обходятся за один проход.

Первое открытие случилось ещё до всяких графиков. Сессия, которая ничего не делает, всё равно держит 0,5–0,7 ГБ. Это сам claude, примерно 300–450 МБ, плюс набор MCP-серверов на node, у каждой сессии свой. Пятнадцать забытых окон — несколько гигабайт, которые просто лежат.

В пейне это выглядит так. У каждой сессии CPU, память и график за шесть минут, отдельным блоком идут сироты, о них ниже, а в самом конце всё, что к сессиям не относится, свёрнутое по имени. Строчка вроде chrome ×31 иногда сразу снимает с Claude все подозрения.

Пейн claude-load: CPU и RAM с графиками, сессии, сирота и процессы вне сессий

Пейн claude-load: CPU и RAM с графиками, сессии, сирота и процессы вне сессий

Скриншоты в статье отрисованы на демо-данных: мои настоящие сессии называются по рабочим проектам. На скриншотах интерфейс английский, а вообще он говорит на языке Claude Code, у меня это русский.

Кнопка, которая могла убить чужой процесс

Самое интересное начинается с процессов, которые не принадлежат ни одной сессии, но явно от них остались. Vite, запущенный из сессии, которую я давно закрыл. Языковой сервер без редактора. Тот самый забытый Python. Хотелось показать их отдельно и дать завершить одной кнопкой.

Первая версия была простой: сирота — любой dev-процесс вне сессий с заметной нагрузкой. Продержалась она до ревью, о котором ниже. Оказалось, что в сироты попадают мой живой PowerShell, помощники IDE и conhost, а кнопка рядом с ними честно предлагает завершить их вместе со всем деревом потомков.

Тот же проход нашёл вещь похуже. Кнопка «завершить» верила снимку в памяти, а он мог быть сколько угодно старым, и имя процесса она не сверяла. Между снимком и нажатием PID успевает освободиться и достаться кому-то другому. Тогда taskkill /T прилетел бы в совершенно посторонний процесс вместе с его детьми.

Теперь всё строже. Сирота — это дерево, у корня которого родитель действительно мёртв. На Windows это значит, что родительского PID нет среди живых или что процесс с этим PID создан позже ребёнка, то есть номер уже переиспользован. На macOS и Linux корень переподчинён init, systemd или launchd. Дерево показывается, только если в нём есть настоящий инструмент разработки, а не одни оболочки, и если оно ест хотя бы 0,3% CPU или 150 МБ. Терминал, из которого запущена сессия, и сам сэмплер сиротами не бывают никогда.

Чтобы сироту было к чему приписать, нужен её рабочий каталог. На Linux он лежит в /proc/<pid>/cwd, на macOS его отдаёт lsof. На Windows готового API нет, и каталог приходится читать из памяти чужого процесса: NtQueryInformationProcess даёт адрес PEB, оттуда по смещению 0x20 берутся ProcessParameters, а в них по 0x38 лежит CurrentDirectory. Звучит страшнее, чем есть: это пара вызовов ReadProcessMemory.

А перед самим завершением мод берёт свежий снимок, отказывается работать, если тот старше 15 секунд, и проверяет, что под этим PID всё ещё процесс с тем же именем. Процессы самих сессий и PID, которых нет в снимке, из пейна не завершить вообще. Так что, если нажать «Да, завершить» через полчаса после открытия пейна, ничего страшного не случится.

Монитор не должен стать частью проблемы

Если каждая из пятнадцати сессий начнёт сама опрашивать процессы, монитор нагрузки сам станет нагрузкой. Поэтому замеряет ровно один процесс на машину. Он пишет ~/.claude/state/load/snapshot.json, а мод в каждой сессии только читает этот файл раз в пять секунд. Сессий может быть сколько угодно, стоимость от этого не растёт.

На Windows сэмплер — скрытый процесс PowerShell, его запускает мод, когда видит, что снимок устарел. Всю конструкцию определили два замера на моей машине: Get-Process отрабатывает за 76 мс, а полный запрос CIM с родителями занимает 400 мс. Поэтому каждые четыре секунды читается дешёвый Get-Process, а дерево родителей из CIM запрашивается, только когда появились новые PID, и не чаще раза в восемь секунд. Доля CPU считается по разнице накопленного времени между проходами.

Живёт сэмплер, пока его кто-то ждёт. Каждая сессия раз в 30 секунд трогает файл wanted, и через три минуты без отметок сэмплер выходит сам. Если он упал, первая же сессия заметит старый снимок и запустит новый, а PID-файл с проверкой командной строки не даст запустить второй. На машине с 12 потоками и 15 сессиями всё это стоит около 0,35% CPU и 130 МБ памяти.

На macOS и Linux отдельный процесс не нужен, ps и так дешёвый. Там мод одной из сессий держит «аренду» — файл со своим ID и временем — и сам снимает нагрузку. Если аренду не обновляли 15 секунд, её забирает другая сессия. С CPU пришлось повозиться. Колонка %cpu в Linux показывает среднее за всю жизнь процесса, поэтому считать приходится по разнице колонки time. А time Linux отдаёт в целых секундах, и два прохода с разницей в секунду рисуют всплески, которых не было. Так что проходы идут не чаще раза в четыре секунды и никогда не накладываются друг на друга.

Мод, движок и пять отказов

Моды появились в Claude Code с версии 2.1.287. Это новый вид плагина: один TypeScript-модуль, который вешает хуки прямо внутри процесса агента. Хук выглядит как ($, e, next), где $ — интерфейс движка с файлами, процессами, таймерами, хранилищем и UI, e — событие, а next передаёт его дальше. Ни Node, ни DOM у модуля нет, всё внешнее идёт через $. Интерфейс собирается из JSX: в терминале есть Box, Text и Button, на десктопе вдобавок Svg.

claude-load держится на пяти точках. session.start заводит таймер и регистрирует /load, command.run отвечает на команду, ui.render рисует пейн и строку над полем ввода, а $.prompt.submit отправляет в сессию просьбу разобраться с нагрузкой. Строка над вводом появляется сама, когда CPU переваливает за 50% или память за 85%, и показывает главных потребителей:

Строка нагрузки над полем ввода

Строка нагрузки над полем ввода

На десктопе графики честные, на SVG. В терминале те же данные рисуются символами ▁▂▃▅▇, а /load печатает короткий отчёт:

Отчёт /load в терминале

Отчёт /load в терминале

Перед загрузкой движок статически разбирает модуль, и часть его правил я узнал только из отказов. Сначала он не принял функцию, которой я передавал $ внутри замыкания: $ можно отдавать только функциям верхнего уровня того же файла. Пришлось вынести состояние в отдельный объект, а функции поднять наверх. Потом выяснилось, что и через import $ не передаётся, так что в остальных файлах остались только чистые функции. $.env.get принимает имя переменной только литералом, и $.env.get(win ? 'USERPROFILE' : 'HOME') превратился в тернарник из двух вызовов. Link открывает только https, поэтому переход в другую сессию по claude:// стал кнопкой, которая просит ОС открыть ссылку. А borderTop у Box просто нет, и линия под заголовком уступила место заголовку капсом.

Хорошая новость: у модов есть настоящий тестовый кит. claude plugin test гоняет мод на живом движке с подменёнными файлами, процессами, часами и даже нажатиями на кнопки пейна. Ошибку с $.env.get поймал именно тест, claude plugin validate её пропустил. Есть и подвох: кит разрешает пути на ОС хоста, и в тесте Linux-ветки на Windows /home/u приходил в мок как C:\home\u. Моку пришлось нормализовать их обратно. В итоге набралось 59 тестов: парсеры ps, vm_stat, /proc/meminfo и lsof, аренда, фильтры, подтверждение завершения и все восемь языков на обеих поверхностях.

Код писал не я

В заголовке стоит «написал», и это преувеличение: руками я его почти не писал. Мод целиком сделан в Claude Code (Opus 5.5) за пару дней, а я был заказчиком и придирчивым рецензентом. Мои реплики в истории сессии в основном такие: «сделай красивее», «добавь фильтры», «очень некрасиво выглядит». Последнее — про строку над вводом, после него она и получила SVG-график и цветные CPU и RAM.

Больше всего пользы дала оркестрация. Основная сессия держала архитектуру и раздавала задачи субагентам, каждому свои файлы, чтобы они не дрались за один код. Один написал сэмплер для macOS и Linux вместе с тестами на записанном выводе команд: проверить его на моей Windows-машине иначе было нечем. Другие перевели интерфейс и README. Словари типизированы, так что забытый ключ ловит тест, а формы множественного числа берутся из Intl.PluralRules: «1 сессия», «3 сессии», «15 сессий».

Перед публикацией был один проход ревью Opus по всему репозиторию. Про сирот и переиспользованный PID я уже рассказал, это его находки. Всего он сам исправил девять локальных дефектов, каждый с тестом. Например, путь к профилю с апострофом вроде C:\Users\O'Brien ломал команду запуска сэмплера, а проходы на Linux могли накладываться и рисовать фальшивые всплески. Решения по дизайну он не трогал, а вернул мне.

Даже скриншоты для README сделал Claude. Он сверстал HTML-макет с теми же SVG-иконками и графиками, что в моде, и снял его в headless-Chrome. Настоящие скриншоты с названиями моих рабочих проектов в публичный репозиторий попасть не должны были.

Двенадцать окон в архив

Первый разбор сработал сразу. Кнопка «Разобрать с Claude» отправляет запрос встроенному скиллу, и Claude раскладывает простаивающие сессии и сирот, спрашивает один раз и трогает только одобренное. Из 15 живых сессий в архив ушли 12: восемь со смёрженными PR и четыре забытые без PR. Занятая память упала с 35,2 до 31,2 ГБ. Заодно я включил в десктопном приложении автоархивацию сессии при мёрже её PR, чтобы забытые окна больше не копились.

Теперь о том, чего мод не умеет. На настоящем Mac или Linux он ещё не запускался: всё покрыто тестами на записанном выводе ps, vm_stat, /proc/meminfo и lsof, но это не одно и то же. CPU на Linux считается грубее, чем на Windows, потому что ps отдаёт время в целых секундах; чтение /proc/<pid>/stat это бы исправило. Строгая политика PowerShell, AllSigned или Constrained Language Mode, не даст сэмплеру стартовать, и мод так и напишет вместо вечного «Жду…».

Ещё два риска от меня не зависят. Реестр сессий не документирован, и если Anthropic поменяет формат ~/.claude/sessions, мод придётся обновлять. А рабочий каталог на Windows читается из памяти чужого процесса. Это только чтение и только своих процессов, но антивирусу или EDR такое может не понравиться. Всё остальное остаётся на машине: ни сетевых запросов, ни телеметрии.

Как попробовать

Нужен Claude Code 2.1.287 или новее. Одна команда добавляет репозиторий как маркетплейс и ставит мод для вашего пользователя. В macOS, Linux и Git Bash:

claude plugin marketplace add Gerrux/claude-load && claude plugin install claude-load@claude-load --config language=auto

В PowerShell:

claude plugin marketplace add Gerrux/claude-load; if ($?) { claude plugin install claude-load@claude-load --config language=auto }

В десктопном приложении можно обойтись без терминала: «+» рядом с полем ввода → Plugins → Add marketplace → Gerrux/claude-load → Add plugin. После установки выполните /reload-plugins и /load. Код лежит на GitHub под MIT, там же README на русском, а про сами моды есть документация Claude Code.

А сколько сессий держите открытыми вы? Если вы на Mac или Linux, напишите, что показал /load и что сломалось: сейчас для мода это самая полезная обратная связь.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.