resource no Python: limites de CPU e memória

Publicado em: 26/08/2026
Tempo de leitura: 7 minutos
A CPU and RAM sticks displayed on a white surface, showcasing computer hardware components.

O módulo resource mede e limita recursos consumidos por processos Unix. Ele permite consultar tempo de CPU, page faults, mudanças de contexto e pico de memória, além de definir cotas para file descriptors, tamanho de arquivos, endereço virtual, processos filhos e outros recursos suportados pelo sistema.

Esses limites são especialmente úteis ao executar plugins, conversores, tarefas de usuários, compiladores ou subprocessos que não devem consumir CPU, memória ou arquivos indefinidamente. Eles não substituem isolamento por container, cgroup, sandbox ou usuário dedicado, mas adicionam uma camada importante de defesa.

Disponibilidade

resource está disponível em Unix e não em WASI. As constantes variam por sistema; uma aplicação deve testar com hasattr().

import resource

if hasattr(resource, "RLIMIT_AS"):
    print(resource.getrlimit(resource.RLIMIT_AS))

Não presuma que Linux, macOS e BSD oferecem os mesmos limites ou que os aplicam da mesma forma.

Soft limit e hard limit

Cada recurso possui um par (soft, hard). O soft limit é o valor aplicado atualmente. O processo pode reduzi-lo e, normalmente, aumentá-lo até o hard limit. O hard limit não pode ser elevado sem privilégios adequados.

soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
print("Soft:", soft, "Hard:", hard)

RLIM_INFINITY representa ilimitado quando o sistema permite.

Não reduza o hard limit sem necessidade

Depois de baixar o hard limit, um processo sem privilégios não consegue restaurá-lo. Para limitações temporárias no próprio processo, preserve o hard limit e altere somente o soft.

soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
resource.setrlimit(resource.RLIMIT_NOFILE, (min(256, hard), hard))

Mesmo alterar o soft limit do processo principal pode quebrar bibliotecas carregadas depois. Em geral, aplique cotas dentro de um subprocesso dedicado.

Limitar file descriptors

RLIMIT_NOFILE controla quantos descriptors podem ficar abertos.

def limitar_fds(maximo=128):
    soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
    novo = min(maximo, hard)
    resource.setrlimit(resource.RLIMIT_NOFILE, (novo, hard))

Ao atingir o limite, operações podem gerar OSError com EMFILE. Feche arquivos, sockets e pipes corretamente; não use a cota como substituto de cleanup.

Limitar CPU

RLIMIT_CPU limita segundos de CPU, não tempo de relógio.

resource.setrlimit(resource.RLIMIT_CPU, (2, 3))

Ao ultrapassar o soft limit, o sistema envia SIGXCPU. Se o processo continuar e atingir o hard limit, pode ser encerrado.

Uma tarefa que dorme ou espera rede pode durar muito mais que dois segundos sem consumir dois segundos de CPU. Use timeout externo para tempo total.

Tratar SIGXCPU

import signal


def cpu_excedida(signum, frame):
    registrar_estado_minimo()
    raise SystemExit(124)

if hasattr(signal, "SIGXCPU"):
    signal.signal(signal.SIGXCPU, cpu_excedida)

O handler deve ser curto. O guia de signal no Python explica por que locks e logging complexo podem ser perigosos em handlers.

Limitar tamanho de arquivos

RLIMIT_FSIZE limita o tamanho máximo de arquivos criados pelo processo.

resource.setrlimit(resource.RLIMIT_FSIZE, (10 * 1024 * 1024, 10 * 1024 * 1024))

Isso reduz risco de uma tarefa preencher o disco com um único arquivo, mas não limita o número total de arquivos nem espaço já existente. Use quota de filesystem ou diretório isolado para proteção mais completa.

Limitar address space

RLIMIT_AS limita o espaço de endereçamento virtual.

if hasattr(resource, "RLIMIT_AS"):
    limite = 512 * 1024 * 1024
    resource.setrlimit(resource.RLIMIT_AS, (limite, limite))

Bibliotecas científicas, mmap, shared libraries e alocadores reservam espaço virtual que não corresponde ao RSS real. Um valor muito baixo pode impedir imports ou gerar MemoryError antes do trabalho começar.

RLIMIT_DATA e RLIMIT_RSS

RLIMIT_DATA limita tradicionalmente o heap, mas nem todas as alocações modernas passam por ele. RLIMIT_RSS pode ser apenas uma sugestão ou não ser aplicado de forma rígida.

Para memória em produção, cgroups ou limites do container costumam ser mais previsíveis que um único rlimit.

Stack

RLIMIT_STACK limita a stack da thread principal. Reduzi-lo demais pode causar crash em recursão, extensões C ou inicialização de bibliotecas.

Ele não é uma forma segura de controlar recursão Python. Use também sys.setrecursionlimit() com cautela.

Número de processos

RLIMIT_NPROC limita processos para o usuário ou processo conforme a plataforma.

if hasattr(resource, "RLIMIT_NPROC"):
    soft, hard = resource.getrlimit(resource.RLIMIT_NPROC)
    resource.setrlimit(resource.RLIMIT_NPROC, (min(32, hard), hard))

Threads podem ou não entrar nessa contagem dependendo do sistema. Containers e serviços compartilhando usuário também podem competir pela mesma cota.

Aplicar limites em subprocessos

Em Unix, subprocess.Popen() aceita preexec_fn, mas seu uso é perigoso em processos multithread. Prefira um executável wrapper simples que aplica limites e depois chama exec.

# wrapper_limitado.py
import os
import resource
import sys

resource.setrlimit(resource.RLIMIT_CPU, (2, 3))
resource.setrlimit(resource.RLIMIT_FSIZE, (10_000_000, 10_000_000))
os.execvp(sys.argv[1], sys.argv[1:])

O processo pai inicia esse wrapper com uma lista de argumentos, sem shell.

prlimit()

Em Linux, prlimit() consulta ou altera limites de outro processo quando há permissão.

if hasattr(resource, "prlimit"):
    anterior = resource.prlimit(pid, resource.RLIMIT_NOFILE, (128, 128))
    print(anterior)

Pode gerar ProcessLookupError se o PID desapareceu e PermissionError sem capacidade suficiente. PIDs podem ser reutilizados; confirme identidade.

Auditoria

setrlimit() e prlimit() geram eventos de auditoria. Ambientes controlados podem registrar ou bloquear alterações.

getrusage()

getrusage() retorna métricas do processo atual, filhos já coletados ou thread atual quando suportado.

uso = resource.getrusage(resource.RUSAGE_SELF)
print("CPU usuário:", uso.ru_utime)
print("CPU sistema:", uso.ru_stime)
print("Pico RSS:", uso.ru_maxrss)

RUSAGE_SELF soma todas as threads do processo. RUSAGE_CHILDREN inclui filhos encerrados e aguardados. RUSAGE_THREAD pode medir apenas a thread atual.

Unidade de ru_maxrss

A unidade de ru_maxrss depende da plataforma. Linux normalmente reporta KiB; macOS reporta bytes. Não compare ou exiba como MB sem normalizar pelo sistema.

import platform

valor = uso.ru_maxrss
bytes_rss = valor if platform.system() == "Darwin" else valor * 1024

Documente essa aproximação e valide em outros Unix.

Pico não é memória atual

ru_maxrss representa o máximo observado, não o consumo atual. Depois que a aplicação libera memória, o valor não diminui.

Para série temporal, use métricas do sistema, procfs, psutil ou observabilidade do container.

Tempo de CPU

ru_utime mede tempo em user mode e ru_stime em kernel mode.

antes = resource.getrusage(resource.RUSAGE_SELF)
executar_trabalho()
depois = resource.getrusage(resource.RUSAGE_SELF)

cpu = (depois.ru_utime - antes.ru_utime) + (depois.ru_stime - antes.ru_stime)

Isso mede CPU acumulada e não substitui benchmark repetível. Para microbenchmarks, use timeit.

Page faults

ru_minflt conta faults que não exigiram I/O; ru_majflt conta aqueles que exigiram acesso a armazenamento.

Os números ajudam a comparar cargas, mas dependem de cache, kernel e ambiente. Uma execução isolada não prova regressão.

Context switches

ru_nvcsw conta trocas voluntárias e ru_nivcsw involuntárias. Muitas involuntárias podem indicar competição por CPU; muitas voluntárias podem refletir espera ou sincronização.

Operações de bloco

ru_inblock e ru_oublock representam operações de entrada e saída em bloco quando a plataforma fornece a métrica. Não interprete como bytes.

Filhos precisam ser aguardados

Para aparecer em RUSAGE_CHILDREN, o processo filho precisa ter terminado e sido coletado com wait() ou waitpid().

Evite zombies e meça depois do wait.

Tamanho de página

getpagesize() retorna o tamanho de página usado pelo sistema.

pagina = resource.getpagesize()
print(pagina)

Ele pode ser útil para alinhamento e estimativas, mas não necessariamente corresponde a todas as huge pages ou detalhes de hardware.

Limites não são sandbox

Um processo limitado ainda pode acessar arquivos permitidos, rede, variáveis de ambiente e credenciais. Combine rlimits com usuário sem privilégio, diretório isolado, allowlist de executáveis, seccomp/capsicum quando disponível e container.

Ordem de aplicação

Aplique limites antes de carregar ou executar conteúdo não confiável. Depois que a tarefa abriu milhares de arquivos ou alocou memória, reduzir a cota não desfaz o consumo existente.

Logs e diagnóstico

Registre os limites efetivos no início do filho. Ao detectar término por sinal, converta o status e informe se CPU, arquivo ou memória podem ter sido responsáveis.

Não assuma que todo SIGKILL veio de OOM; o operador também pode ter enviado o sinal.

Testes

Teste constantes ausentes, soft maior que hard, tentativa de elevar hard limit, CPU-bound, sleep, criação de arquivo, muitos descriptors, import de bibliotecas sob RLIMIT_AS, filhos, threads, Linux/macOS e container.

Erros comuns

Os erros mais frequentes são aplicar limites no processo principal, confundir CPU com tempo total, tratar ru_maxrss como memória atual, ignorar unidade por plataforma, reduzir hard limit sem retorno, presumir RLIMIT_RSS rígido e considerar rlimit uma sandbox completa.

Conclusão

resource mede consumo e impõe cotas Unix básicas. Ele funciona melhor em subprocessos dedicados, com limites definidos antes do trabalho e observação externa de timeout e memória.

Teste cada constante no sistema alvo, normalize métricas e combine rlimits com isolamento real. Consulte a documentação oficial de resource e o manual getrlimit(2).

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Close-up of a parking payment terminal in an indoor garage in Almere, Netherlands.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pty no Python: automatize terminais Unix

    Aprenda pty no Python para executar e testar programas interativos, controlar pseudo-terminais, tratar EOF, resize, sinais e timeouts.

    Ler mais

    Tempo de leitura: 6 minutos
    25/08/2026
    A close-up shot showcasing the intricate scales of a snake, highlighting texture and color.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tty no Python: modos raw e cbreak

    Aprenda tty no Python para usar raw e cbreak, ler teclas, tratar sequências, Unicode e restaurar o terminal Unix com

    Ler mais

    Tempo de leitura: 6 minutos
    25/08/2026
    Multiple padlocks securing a green chain link fence, symbolizing safety and protection.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    termios no Python: controle seguro do terminal

    Aprenda termios no Python para modo canônico, echo, leitura por tecla, baud rate, filas e restauração segura do terminal POSIX.

    Ler mais

    Tempo de leitura: 6 minutos
    25/08/2026
    Detailed close-up of a combination lock with numbers in focus, highlighting security and privacy.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    fcntl no Python: locks e controle de arquivos

    Aprenda fcntl no Python para locks, flags de descritores, ioctl, pipes e controle Unix, evitando buffers incorretos e corrupção de

    Ler mais

    Tempo de leitura: 6 minutos
    25/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    readline no Python: histórico e autocomplete

    Aprenda readline no Python para histórico, autocomplete, edição de linha, GNU Readline, libedit e prompts seguros no terminal.

    Ler mais

    Tempo de leitura: 6 minutos
    25/08/2026
    Serene stream flowing through Bavarian mountains, capturing winter beauty and natural tranquility.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    io no Python: domine streams e buffers

    Aprenda io no Python para trabalhar com streams de texto e bytes, buffering, encoding, StringIO, BytesIO e I/O bruto com

    Ler mais

    Tempo de leitura: 7 minutos
    24/08/2026