mmap no Python: arquivos em memória

Publicado em: 09/08/2026
Tempo de leitura: 7 minutos
Disco rígido representando arquivos mapeados em memória com mmap no Python

Arquivos grandes podem ser acessados sem carregar todo o conteúdo manualmente em uma única chamada de leitura. O módulo mmap no Python cria um mapeamento entre uma região do arquivo e o espaço de memória virtual do processo. O objeto resultante se comporta ao mesmo tempo como um arquivo e como um array mutável de bytes.

Esse recurso é útil em busca de padrões, índices binários, bancos embarcados, comunicação entre processos e edição de regiões fixas. Ele não torna toda operação automaticamente mais rápida e exige atenção a permissões, alinhamento, concorrência, tamanho do arquivo e persistência. Neste guia você aprenderá os modos de acesso, leitura, escrita, copy-on-write, memória anônima e diferenças entre plataformas.

O conteúdo complementa nossos artigos sobre fileinput, linecache, tempfile, filecmp e weakref.

Como o mapeamento funciona

O sistema operacional associa páginas do arquivo a endereços virtuais. As páginas são carregadas sob demanda. O código acessa bytes por índice, slice ou métodos semelhantes aos de arquivos.

O benefício principal é deixar o kernel gerenciar paginação e cache. O custo ainda existe: páginas precisam ser lidas, falhas de página podem ocorrer e acessos aleatórios podem ser caros.

Mapear um arquivo inteiro para leitura

import mmap

with open("dados.bin", "rb") as arquivo:
    with mmap.mmap(
        arquivo.fileno(),
        length=0,
        access=mmap.ACCESS_READ,
    ) as memoria:
        print(memoria[:16])

length=0 significa mapear o tamanho atual do arquivo em plataformas suportadas. No Windows, arquivos vazios não podem ser mapeados dessa forma.

Acesso somente leitura

ACCESS_READ impede alterações. Uma tentativa de atribuição gera TypeError.

memoria[0] = 65  # TypeError em mapa somente leitura

Prefira esse modo quando o objetivo é pesquisar ou analisar. Ele reduz o risco de modificar o arquivo por engano.

Acesso com escrita persistente

with open("dados.bin", "r+b") as arquivo:
    with mmap.mmap(
        arquivo.fileno(),
        0,
        access=mmap.ACCESS_WRITE,
    ) as memoria:
        memoria[0:4] = b"HEAD"
        memoria.flush()

Em ACCESS_WRITE, alterações afetam o mapeamento e o arquivo subjacente. O slice substituído precisa ter o mesmo tamanho; o mmap não funciona como uma lista que cresce durante a atribuição.

Copy-on-write

with open("dados.bin", "rb") as arquivo:
    with mmap.mmap(
        arquivo.fileno(),
        0,
        access=mmap.ACCESS_COPY,
    ) as memoria:
        memoria[0:4] = b"TEST"

As alterações ficam privadas no mapeamento e não são gravadas no arquivo. Esse modo é útil para experimentos e transformações temporárias, mas não deve ser confundido com uma cópia completa criada antecipadamente.

Flushing do arquivo antes do mapa

Se um arquivo gravável possui dados em buffers do Python, chame flush() antes de criar o mapeamento.

arquivo.write(b"conteudo")
arquivo.flush()
memoria = mmap.mmap(arquivo.fileno(), 0)

Isso garante que as alterações locais estejam disponíveis para o mecanismo de mapeamento.

Pesquisar bytes

posicao = memoria.find(b"ERRO")
if posicao != -1:
    print("encontrado em", posicao)

find() e rfind() aceitam intervalos. O módulo re também pode pesquisar diretamente no objeto mmap.

Usar expressões regulares

import re

for match in re.finditer(rb"ID:\d+", memoria):
    print(match.start(), match.group())

Use padrões de bytes, não strings Unicode. A interpretação de texto exige conhecer o encoding e respeitar limites entre caracteres multibyte.

Métodos de arquivo

Objetos mmap possuem posição corrente e métodos como read(), readline(), seek(), tell() e write().

memoria.seek(0)
primeira_linha = memoria.readline()
posicao = memoria.tell()

No Python 3.13, seek() passou a devolver a nova posição absoluta.

Acesso por índice e slice

primeiro = memoria[0]       # inteiro
cabecalho = memoria[0:16]  # bytes

Atribuir um índice exige um inteiro de byte. Atribuir um slice exige bytes de comprimento compatível.

Persistência com flush

flush() solicita que alterações sejam enviadas ao armazenamento.

memoria.flush()

Também é possível informar offset e tamanho, mas o offset precisa estar alinhado a PAGESIZE ou ALLOCATIONGRANULARITY. Verifique exceções; não presuma sucesso.

Durabilidade real

Flush do mmap e sincronização do descritor são conceitos relacionados, mas requisitos de durabilidade variam por sistema de arquivos. Aplicações transacionais precisam estudar fsync, ordem de escrita e substituição atômica.

Mmap não transforma automaticamente um arquivo em banco de dados seguro contra falhas.

Offsets alinhados

O parâmetro offset deve ser múltiplo de ALLOCATIONGRANULARITY. Para mapear uma região arbitrária, alinhe o início para baixo e aplique um deslocamento interno.

gran = mmap.ALLOCATIONGRANULARITY
base = inicio // gran * gran
delta = inicio - base
comprimento = delta + tamanho

Depois acesse memoria[delta:delta+tamanho].

Mapas maiores e menores

O comprimento define a região visível. size() pode devolver o tamanho do arquivo, que pode ser maior que o mapa. len(memoria) representa o tamanho mapeado.

Não acesse além do limite; o Python gera erros, e mudanças concorrentes no tamanho do arquivo podem ter comportamento dependente da plataforma.

Redimensionar

resize() altera o mapa e, quando aplicável, o arquivo. Mapas read-only, copy-on-write ou criados com trackfd=False não podem ser redimensionados.

No Windows, outros mapas do mesmo arquivo podem impedir a operação. Coordene redimensionamentos de forma exclusiva.

trackfd no Unix

Desde Python 3.13, o construtor Unix aceita trackfd=False. Nesse modo, o descritor não é duplicado e métodos como size() e resize() deixam de funcionar.

Isso ajuda processos com muitos mapeamentos e limite de descritores, mas transfere mais responsabilidade para a aplicação.

Memória anônima

with mmap.mmap(-1, 4096) as memoria:
    memoria.write(b"dados temporarios")

Passar -1 como descritor cria uma região não associada a arquivo. Ela pode servir como buffer e, em alguns modelos de processos, como memória compartilhada.

Compartilhamento entre processos

Em Unix, um mapa anônimo criado antes de fork() pode ser compartilhado entre pai e filho. Em aplicações portáveis, mecanismos de multiprocessing.shared_memory podem oferecer uma API mais explícita.

Memória compartilhada não inclui sincronização. Use locks, semáforos ou protocolos atômicos adequados.

MAP_SHARED e MAP_PRIVATE

No construtor Unix de baixo nível, MAP_SHARED permite que alterações sejam vistas por outros processos que mapearam a mesma área. MAP_PRIVATE cria copy-on-write.

Não combine access com flags e prot na mesma chamada; isso é erro.

Diferenças no Windows

O construtor Windows pode receber tagname para mapeamentos nomeados, mas evitar essa opção melhora portabilidade. O offset também precisa respeitar a granularidade de alocação.

Mapear comprimento maior que o arquivo pode estendê-lo no Windows. Não dependa dessa diferença sem testes específicos.

madvise

Em sistemas com suporte, madvise() informa ao kernel o padrão esperado de acesso.

if hasattr(memoria, "madvise"):
    memoria.madvise(mmap.MADV_SEQUENTIAL)

Constantes disponíveis variam por sistema. Trate a otimização como opcional e meça seu impacto.

Acesso sequencial e aleatório

Mapear não elimina o custo do disco. Uma varredura sequencial tende a aproveitar prefetch. Acessos aleatórios em um arquivo muito maior que a RAM podem causar muitas falhas de página.

Faça benchmark com o conjunto real e observe memória residente, page faults e latência.

Concorrência

Dois processos podem alterar a mesma região e criar corrupção lógica. O sistema garante coerência de memória em certo nível, mas não protege invariantes da aplicação.

Defina cabeçalhos, versões, locks e protocolo de commit. Nunca presuma que uma sequência de writes é atômica.

Arquivo truncado por outro processo

Se outro processo encurta um arquivo mapeado, acessos posteriores podem falhar de maneira severa ou específica do sistema. Controle propriedade e ciclo de vida do arquivo.

Fechar recursos

Use context managers para fechar o mmap. Fechar o mapa não fecha automaticamente o objeto de arquivo original.

with open("dados.bin", "rb") as arquivo:
    with mmap.mmap(arquivo.fileno(), 0, access=mmap.ACCESS_READ) as memoria:
        processar(memoria)

Views de memória ativas podem impedir fechamento. Libere referências antes de sair.

Segurança

Mapear um arquivo não valida seu conteúdo. Comprimentos, offsets e estruturas internas podem ser maliciosos. Verifique limites antes de usar valores do próprio arquivo para calcular slices.

Não mapeie dispositivos ou arquivos especiais sem compreender os efeitos. O módulo gera um evento de auditoria na criação do mapa.

Testes

Teste arquivos vazios, pequenos, grandes, read-only, copy-on-write, offsets alinhados, busca ausente, flush, concorrência controlada e comportamento em Windows e Unix.

Erros frequentes

  • Mapear um arquivo vazio no Windows.
  • Esquecer de abrir com modo compatível.
  • Não fazer flush do buffer antes do mapeamento.
  • Usar offset não alinhado.
  • Presumir que flush() garante uma transação.
  • Escrever slices com tamanho diferente.
  • Redimensionar enquanto outros mapas existem.
  • Usar memória compartilhada sem sincronização.

Boas práticas

  • Use ACCESS_READ por padrão.
  • Escolha copy-on-write para alterações temporárias.
  • Valide tamanhos e offsets.
  • Feche mapas com with.
  • Meça padrões de acesso reais.
  • Sincronize escritores concorrentes.
  • Teste diferenças de plataforma.
  • Não trate mmap como banco transacional.

Conclusão

O módulo mmap no Python oferece acesso eficiente e flexível a arquivos e regiões de memória. Ele combina slicing de bytes, métodos de arquivo, pesquisa e compartilhamento controlado.

O desempenho depende do padrão de acesso e do sistema operacional. Use modos mínimos de permissão, alinhe offsets, valide estruturas e coordene concorrência. Consulte a documentação oficial de mmap e a documentação do mmap em sistemas Unix para detalhes de baixo nível.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Código e compilador representando caminhos e variáveis de build com sysconfig no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sysconfig no Python: caminhos e build

    Aprenda sysconfig no Python para descobrir caminhos de instalação, variáveis de build, headers, virtualenvs e plataformas com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    09/08/2026
    Código-fonte representando tokens e constantes do parser com o módulo token no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    token no Python: constantes do parser

    Aprenda token no Python para interpretar tipos léxicos, operadores exatos, f-strings, t-strings e árvores sintáticas por versão.

    Ler mais

    Tempo de leitura: 8 minutos
    07/08/2026
    Código-fonte representando palavras reservadas e soft keywords no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    keyword no Python: palavras reservadas

    Aprenda keyword no Python para validar identificadores, palavras reservadas e soft keywords conforme a versão do interpretador.

    Ler mais

    Tempo de leitura: 7 minutos
    07/08/2026
    Arquitetura de software representando classes abstratas com abc no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    abc no Python: classes abstratas

    Aprenda abc no Python para criar classes abstratas, métodos obrigatórios, subclasses virtuais e contratos de runtime.

    Ler mais

    Tempo de leitura: 6 minutos
    06/08/2026
    Código e estruturas representando tipos do runtime com o módulo types no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    types no Python: tipos do runtime

    Aprenda types no Python para usar SimpleNamespace, MappingProxyType, tipos do runtime e criação dinâmica de classes.

    Ler mais

    Tempo de leitura: 6 minutos
    06/08/2026
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sched no Python: agende eventos

    Aprenda sched no Python para agendar eventos, controlar prioridades, cancelar tarefas e criar repetições com relógio monotônico.

    Ler mais

    Tempo de leitura: 8 minutos
    05/08/2026