Domando o devsense.php.ls: como depurar e conter o consumo de CPU e memória no Linux
Voltar para blog

Domando o devsense.php.ls: como depurar e conter o consumo de CPU e memória no Linux

Atualizado em 20/09/2026 · Publicado em 19/09/2026 · 4 min · Desenvolvimento

O desenvolvimento remoto via SSH utilizando editores modernos tornou-se padrão no dia a dia. No entanto, ferramentas de autocompletar e análise estática executam processos pesados no servidor remoto. Um dos binários que mais frequentemente gera picos de recursos é o devsense.php.ls (o Language Server da extensão PHP da DEVSENSE).

Neste artigo, compartilho o diagnóstico em nível de sistema operacional e as duas frentes aplicadas para neutralizar o impacto desse processo: ajustes no settings.json do editor e controle de recursos no kernel Linux.


1. O problema: gargalos de CPU, memória e i/o#

O devsense.php.ls não é um script PHP interpretado pontualmente. Trata-se de um binário compilado que roda como processo persistente (sidecar) comunicando-se via JSON-RPC através do Language Server Protocol (LSP).

Em bases de código grandes (como Laravel ou Magento), ele pode apresentar os seguintes gargalos:

  1. Picos de CPU e Troca de Contexto: A varredura de árvores sintáticas (AST) eleva drasticamente o context-switch no processador.
  2. Pressão de Memória (RSS): A tabela de símbolos e índices de tipagem aumentam a ocupação da memória RAM.
  3. Esgotamento de File Watchers (inotify): Ao atingir o limite de observadores do kernel, o processo degrada para polling contínuo com chamadas manuais ao disco.
  4. Processos Órfãos: Conexões SSH encerradas abruptamente podem deixar o binário rodando em segundo plano sem cliente ativo.

2. Diagnóstico no terminal com ferramentas de baixo nível#

Para inspecionar o comportamento real do processo:

1. Rastreando chamadas de sistema com strace#

Para checar se o processo está em loop infinito varrendo pastas pesadas (vendor, node_modules):

strace -p <PID> -e trace=file,desc

Para detectar o comportamento de polling excessivo (enxurrada de chamadas lstat):

strace -p <PID> -e trace=lstat | head -n 100

Se o terminal exibir milhares de chamadas lstat contínuas, o processo excedeu o limite do inotify e está varrendo o disco manualmente.

2. Inspecionando memória com pmap#

Para auditar a alocação de Heap e bibliotecas mapeadas:

pmap -x <PID> | sort -n -k3

3. Checando a comunicação IPC e sockets#

Como o Language Server normalmente se comunica via stdio (JSON-RPC através de pipes herdados do editor remoto), ele raramente abre portas de rede convencionais. Inspecione descritores de arquivo, pipes e eventuais sockets locais:

# Listar descritores de arquivo e pipes IPC do processo
ls -l /proc/<PID>/fd

# Inspecionar sockets de rede ou UNIX abertos pelo processo
lsof -p <PID> | grep -E 'unix|FIFO|IPv[46]'

# Listar sockets UNIX locais ativos
ss -xap | grep <PID>

3. Solução em duas frentes#

A contenção foi implementada em duas camadas complementares:

Frente 1: Restringindo o escopo do language server no settings.json#

A forma mais eficiente de evitar varreduras globais é limitar a análise apenas aos arquivos abertos e instruir tanto o LSP quanto o VS Code a ignorar diretórios pesados:

{
  "php.problems.scope": "opened",
  "php.analysis.extractTypes": false,
  "php.stubs.load": false,
  "php.inlayHints.enabled": false,
  "files.watcherExclude": {
    "**/vendor/**": true,
    "**/node_modules/**": true,
    "**/temp/**": true,
    "**/storage/**": true
  }
}

Frente 2: Contenção de recursos no Linux#

Para evitar que sessões concorrentes saturem a máquina:

1. Prioridade de i/o e CPU com ionice e renice#

# Prioridade de I/O para Idle (Classe 3)
ionice -c 3 -p <PID>

# Menor prioridade de agendamento de CPU (Nice +19)
renice +19 -p <PID>

2. Limitação de memória com Cgroups#

Para evitar que o processo cause OOM (Out of Memory) e derrube outros serviços:

# Cgroups v2 (padrão em distribuições modernas como Ubuntu 22.04+, Debian 12+, RHEL 9+)
sudo mkdir -p /sys/fs/cgroup/devsense_limit
echo 536870912 | sudo tee /sys/fs/cgroup/devsense_limit/memory.max
echo <PID> | sudo tee /sys/fs/cgroup/devsense_limit/cgroup.procs

# Cgroups v1 (ambientes legados com libcgroup-tools)
sudo cgcreate -g memory:devsense_limit
echo 512M | sudo tee /sys/fs/cgroup/memory/devsense_limit/memory.limit_in_bytes
sudo cgclassify -g memory:devsense_limit <PID>

3. Aumentar o limite de observadores do inotify#

Para evitar a degradação para loops de lstat:

# Aplicação imediata
sudo sysctl -w fs.inotify.max_user_watches=524288

# Configuração persistente (sobrevive a reboots)
echo "fs.inotify.max_user_watches = 524288" | sudo tee /etc/sysctl.d/90-inotify.conf
sudo sysctl --system

Referência de métricas para monitoramento#

MétricaComportamento SaudávelSinal de Alerta
Resident Set Size (RSS)200 MB a 1 GB (estável)Crescimento linear contínuo (Memory Leak)
File DescriptorsAlto apenas na inicializaçãoPróximo do limite configurado (ulimit -n)
Syscallsfutex, epoll_wait, readLoops contínuos de stat e lstat

Boas práticas para controlar language servers no Linux#

  1. Exclua diretórios de dependências: Sempre adicione vendor/ e node_modules/ nas regras de exclusão de indexação do LSP.
  2. Ajuste o inotify do kernel de forma persistente: Manter max_user_watches alto evita que ferramentas de desenvolvimento degradem para leitura contínua de disco.
  3. Use cgroups em servidores multiusuário: Limitar o consumo de memória de processos remotos garante a estabilidade dos serviços essenciais do host.

Conclusão#

Neste artigo compartilhei as duas frentes que usei para domar o devsense.php.ls: restringir o escopo de análise no editor e conter o processo no kernel — com strace e pmap para confirmar o sintoma antes de agir. A combinação de exclusão de diretórios pesados, cgroup com limite de memória e inotify folgado manteve o host estável com vários desenvolvedores conectados simultaneamente.

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários