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 leituraPrefira 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] # bytesAtribuir 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 + tamanhoDepois 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_READpor 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.






