Acho que a vantagem é realmente que você reduz a quantidade de cópia de dados necessária em relação aos métodos tradicionais de leitura de um arquivo.
Se o seu aplicativo puder usar os dados "no local" em um arquivo mapeado na memória, ele poderá entrar sem ser copiado; se você usar uma chamada de sistema (por exemplo, pread () do Linux), isso normalmente envolve o kernel copiando os dados de seus próprios buffers para o espaço do usuário. Essa cópia extra não só leva tempo, mas diminui a eficácia dos caches da CPU acessando essa cópia extra dos dados.
Se os dados realmente precisam ser lidos do disco (como em E / S física), então o sistema operacional ainda tem que lê-los, uma falha de página provavelmente não é melhor em termos de desempenho do que uma chamada de sistema, mas se eles não (ou seja, já no cache do sistema operacional), o desempenho deveria, em teoria, ser muito melhor.
No lado negativo, não há interface assíncrona para arquivos mapeados na memória - se você tentar acessar uma página que não está mapeada, isso gera uma falha de página e faz com que o thread espere pelo I / O.
A desvantagem óbvia dos arquivos mapeados na memória está em um sistema operacional de 32 bits - você pode facilmente ficar sem espaço de endereço.
Usei um arquivo mapeado de memória para implementar um recurso de 'preenchimento automático' enquanto o usuário está digitando. Tenho bem mais de 1 milhão de números de peças de produtos armazenados em um único arquivo de índice. O arquivo tem algumas informações de cabeçalho típicas, mas a maior parte do arquivo é uma matriz gigante de registros de tamanho fixo classificados no campo-chave.
No tempo de execução, o arquivo é mapeado na memória, lançado em uma matriz de
C
estilostruct
e fazemos uma pesquisa binária para encontrar números de peça correspondentes conforme os tipos de usuário. Apenas algumas páginas da memória do arquivo são realmente lidas do disco - quaisquer que sejam as páginas atingidas durante a pesquisa binária.fonte
Os arquivos mapeados na memória podem ser usados para substituir o acesso de leitura / gravação ou para oferecer suporte ao compartilhamento simultâneo. Quando você os usa para um mecanismo, obtém o outro também.
Em vez de procurar, escrever e ler um arquivo, você o mapeia na memória e simplesmente acessa os bits onde espera que estejam.
Isso pode ser muito útil e, dependendo da interface da memória virtual, pode melhorar o desempenho. A melhoria de desempenho pode ocorrer porque o sistema operacional agora consegue gerenciar esse antigo "arquivo de E / S" junto com todos os outros acessos à memória programática e pode (em teoria) aproveitar os algoritmos de paginação e assim por diante que já está usando para oferecer suporte memória virtual para o resto do programa. No entanto, depende da qualidade do seu sistema de memória virtual subjacente. Eu ouvi dizer que os sistemas de memória virtual Solaris e * BSD podem apresentar melhorias de desempenho melhores do que o sistema VM do Linux - mas não tenho dados empíricos para fazer backup disso. YMMV.
A simultaneidade entra em cena quando você considera a possibilidade de vários processos usando o mesmo "arquivo" por meio da memória mapeada. No modelo de leitura / gravação, se dois processos gravassem na mesma área do arquivo, você poderia ter quase certeza de que um dos dados do processo chegaria no arquivo, sobrescrevendo os dados do outro processo. Você conseguiria um ou outro - mas não uma mistura estranha. Tenho que admitir que não tenho certeza se esse é um comportamento exigido por algum padrão, mas é algo em que você poderia confiar. (Na verdade, é uma boa pergunta de acompanhamento!)
No mundo mapeado, em contraste, imagine dois processos, ambos "escrevendo". Eles fazem isso fazendo "armazenamentos de memória", o que resulta na paginação O / S dos dados para o disco - eventualmente. Mas, enquanto isso, podem ocorrer gravações sobrepostas.
Aqui está um exemplo. Digamos que eu tenha dois processos gravando 8 bytes no deslocamento 1024. O processo 1 está gravando '11111111' e o processo 2 está gravando '22222222'. Se eles usam I / O de arquivo, então você pode imaginar, no fundo do O / S, há um buffer cheio de 1s e um buffer cheio de 2s, ambos indo para o mesmo lugar no disco. Um deles vai chegar lá primeiro, e o outro um segundo. Nesse caso, o segundo ganha. No entanto , se estou usando a abordagem de arquivo mapeado por memória, o processo 1 vai para um armazenamento de memória de 4 bytes, seguido por outro armazenamento de memória de 4 bytes (vamos supor que esse não seja o tamanho máximo de armazenamento de memória). O processo 2 fará a mesma coisa. Com base em quando os processos são executados, você pode esperar ver qualquer um dos seguintes:
A solução para isso é usar a exclusão mútua explícita - o que provavelmente é uma boa ideia em qualquer caso. De qualquer forma, você estava confiando no O / S para fazer "a coisa certa" no caso de I / O de arquivo de leitura / gravação.
A primitiva de exclusão mútua de classificação é o mutex. Para arquivos mapeados na memória, sugiro que você olhe para um mutex mapeado na memória, disponível usando (por exemplo) pthread_mutex_init ().
Edite com uma pegadinha: Quando você está usando arquivos mapeados, existe a tentação de incorporar ponteiros para os dados no arquivo, no próprio arquivo (pense na lista vinculada armazenada no arquivo mapeado). Você não quer fazer isso, pois o arquivo pode ser mapeado em diferentes endereços absolutos em momentos diferentes ou em processos diferentes. Em vez disso, use deslocamentos dentro do arquivo mapeado.
fonte
A simultaneidade seria um problema. O acesso aleatório é mais fácil O desempenho vai de bom para ótimo. Fácil de usar. Não tão bom. Portabilidade - não tão quente.
Eu os usei em um sistema solar há muito tempo, e esses são meus pensamentos.
fonte