Os arquivos são abertos pelos processos carregados na RAM?

24

Comandos , por exemplo sed, são programas e programas são lógicos codificados dentro de um arquivo e esses arquivos estão em algum lugar do disco rígido. No entanto, quando os comandos estão sendo executados, uma cópia de seus arquivos do disco rígido é colocada na RAM , onde eles ganham vida e podem fazer coisas e são chamados de processos .

Os processos podem fazer uso de outros arquivos, ler ou gravar neles e, se o fizerem, serão chamados de arquivos abertos. Existe um comando para listar todos os arquivos abertos por todos os processos em execução: lsof.

OK, então o que me pergunto é se a vida dupla de um comando, um no disco rígido, o outro na RAM também é válido para outros tipos de arquivos, por exemplo, aqueles que não têm lógica programada, mas são simplesmente contêineres para dados.

Meu pressuposto é que os arquivos abertos pelos processos também são carregados na RAM. Não sei se é verdade, é apenas uma intuição.

Por favor, alguém poderia entender isso?

tubarão
fonte

Respostas:

27

No entanto, quando os comandos estão sendo executados, uma cópia de seus arquivos do disco rígido é colocada na RAM,

Isso está errado (em geral). Quando um programa é executado (através de execve (2) ...), o processo (executando esse programa) está alterando seu espaço de endereço virtual e o kernel está reconfigurando o MMU para esse fim. Leia também sobre memória virtual . Observe que os programas aplicativos podem alterar seu espaço de endereço virtual usando mmap (2) e munmap& mprotect (2) , também usados ​​pelo vinculador dinâmico (consulte ld-linux (8) ). Veja também madvise (2) e posix_fadvise (2) e mlock (2) .

Falhas de página futuras serão processadas pelo kernel para carregar (preguiçosamente) páginas do arquivo executável. Leia também sobre thrashing .

O kernel mantém um cache de página grande . Leia também sobre copiar na gravação . Veja também readahead (2) .

OK, então o que me pergunto é se a vida dupla de um comando, um no disco rígido, o outro na RAM também é válido para outros tipos de arquivos, por exemplo, aqueles que não têm lógica programada, mas são simplesmente contêineres para dados.

Para chamadas do sistema como leitura (2) e gravação (2), o cache da página também é usado. Se os dados a serem lidos estiverem nele, nenhuma E / S de disco será feita. Se for necessário E / S de disco, é muito provável que os dados lidos sejam colocados no cache da página. Portanto, na prática, se você executar o mesmo comando duas vezes, pode acontecer que nenhuma E / S física seja feita no disco na segunda vez (se você tiver um disco rígido rotativo antigo - não um SSD), poderá ouvir isso; ou observe cuidadosamente o LED do disco rígido).

Eu recomendo a leitura de um livro como Sistemas operacionais: Three Easy Pieces (que pode ser baixado gratuitamente, um arquivo PDF por capítulo), o que explica tudo isso.

Veja também Linux comeu meus RAM e executar comandos como xosview, top, htopou cat /proc/self/mapsou cat /proc/$$/maps(ver proc (5) ).

PS. Estou focando no Linux, mas outros sistemas operacionais também têm memória virtual e cache de páginas.

Basile Starynkevitch
fonte
35

Não, um arquivo não é lido automaticamente na memória, abrindo-o. Isso seria terrivelmente ineficiente. sed, por exemplo, lê sua entrada linha por linha, assim como muitas outras ferramentas Unix. Raramente tem que manter mais do que a linha atual na memória.

Com awké o mesmo. Ele lê um registro de cada vez, que por padrão é uma linha. Se você armazenar partes dos dados de entrada em variáveis, isso será extra, é claro 1 .

Algumas pessoas têm o hábito de fazer coisas como

for line in $(cat file); do ...; done

Desde que o shell terá de expandir a $(cat file)substituição de comando completamente antes de executar até mesmo a primeira iteração do forloop, este irá ler integralmente filena memória (na memória usada pelo shell de executar o forloop). Isso é um pouco bobo e também deselegante. Em vez disso, deve-se fazer

while IFS= read -r line; do ...; done <file

Isso processará filelinha por linha (mas leia Noções básicas sobre "IFS = leia -r linha" ).

Porém, raramente é necessário processar arquivos linha por linha no shell, pois a maioria dos utilitários é orientada a linhas (consulte Por que usar um loop do shell para processar o texto considerado uma má prática? ).

Estou trabalhando em bioinformática e, ao processar grandes quantidades de dados genômicos, não seria capaz de fazer muito, a menos que mantivesse apenas os bits dos dados que eram absolutamente necessários na memória. Por exemplo, quando preciso extrair os bits de dados que podem ser usados ​​para identificar indivíduos de um conjunto de dados de 1 terabyte contendo variantes de DNA em um arquivo VCF (porque esse tipo de dados não pode ser tornado público), faço linha por linha processamento com um awkprograma simples (isso é possível, pois o formato VCF é orientado a linhas). Eu não ler o arquivo na memória, processá-lo lá, e escrevê-lo de volta novamente! Se o arquivo fosse compactado, eu o alimentaria através de , zcatou gzip -d -c, que, como gzipfaz o fluxo de processamento de dados, também não leria o arquivo inteiro na memória.

Mesmo com formatos de arquivo que não são orientados a linhas, como JSON ou XML, existem analisadores de fluxo que permitem processar arquivos enormes sem armazenar tudo na RAM.

Nos executáveis, é um pouco mais complicado, pois as bibliotecas compartilhadas podem ser carregadas sob demanda e / ou compartilhadas entre processos (consulte Carregamento de bibliotecas compartilhadas e uso de RAM , por exemplo).

O armazenamento em cache é algo que não mencionei aqui. Esta é a ação de usar a RAM para armazenar dados acessados ​​com freqüência. Arquivos menores (por exemplo, executáveis) podem ser armazenados em cache pelo sistema operacional na esperança de que o usuário faça muitas referências a eles. Além da primeira leitura do arquivo, os acessos subsequentes serão feitos à RAM e não ao disco. O armazenamento em cache, como o buffer de entrada e saída, geralmente é bastante transparente para o usuário, e a quantidade de memória usada para armazenar em cache as coisas podem mudar dinamicamente, dependendo da quantidade de RAM alocada pelos aplicativos etc.


1 Tecnicamente, a maioria dos programas provavelmente lê um pedaço dos dados de entrada de cada vez, usando buffer explícito ou implicitamente através do buffer que as bibliotecas de E / S padrão fazem, e então apresenta esse pedaço de linha por linha no código do usuário. É muito mais eficiente ler um múltiplo do tamanho do bloco do disco do que, por exemplo, um caractere de cada vez. Porém, esse tamanho de pedaço raramente será maior que um punhado de kilobytes.

Kusalananda
fonte
você disse que é possível carregar bibliotecas compartilhadas na RAM. Também é possível carregar um arquivo regular, que contém apenas dados na RAM, mesmo que isso não faça sentido?
sharkant
1
@sharkant Claro. Isso é apenas uma questão de adicionar dados a uma variável (ou matriz, hash ou qualquer estrutura de dados fornecida pelo idioma em questão) até que todo o arquivo seja armazenado. Com awk, { a[i++] = $0 }adicionaria todas as linhas do arquivo de entrada à matriz a. Você também pode procurar a função C mmap(), mas seu uso pode ser um pouco fora de tópico aqui.
Kusalananda
6
sed,, awke outros programas orientados a linhas não lêem uma linha de cada vez na memória, porque os arquivos de texto sem formatação não contêm um índice de linha, e as APIs do sistema de arquivos e o hardware de armazenamento de baixo nível lêem um ou mais "setores" (normalmente 512 ou 1024 bytes) por vez. Eu ficaria surpreso se menos de 8 KB fossem lidos na memória pelo sistema operacional antes que a primeira linha fosse processada.
Russell Borogove
5
Embora um utilitário como sedleia apenas uma linha de cada vez na memória, vale ressaltar que o sistema operacional usará ram grátis para armazenar arquivos em cache, para que possam ser acessados ​​rapidamente. Se você estiver executando sedem um arquivo menor, é possível que o sistema operacional armazene em cache o arquivo inteiro na memória e a operação seja realizada inteiramente na RAM. Veja: en.wikipedia.org/wiki/Page_cache
Sean Dawson
5
@sharkant É útil ter um arquivo totalmente acessível na memória (veja a outra resposta, mmap é a palavra-chave chamada do sistema aqui). Por exemplo, um sistema de banco de dados geralmente gostaria de ter, para facilidade e velocidade de acesso, todo o banco de dados ou pelo menos alguns dos índices mapeados na memória. Isso não significa necessariamente que a coisa toda esteja realmente na memória. O sistema operacional é livre para "fingir" que o arquivo está na memória. Ele diz ao aplicativo "aqui, nesta faixa de memória está o seu arquivo", e somente quando uma leitura é feita (assim como quando o processo foi trocado), os dados são realmente lidos.
Jonas Schäfer
5

Não. Embora tenha shows de RAM hoje em dia seja fantástico, houve um tempo em que a RAM era um recurso muito limitado (eu aprendi a programar em um VAX 11/750 com 2 MB de RAM) e a única coisa na RAM era o executável ativo e as páginas de dados de processos ativos e dados de arquivo que estavam no cache do buffer.
O cache do buffer foi liberado e as páginas de dados foram trocadas. E frequentemente às vezes. As páginas executáveis ​​somente leitura foram sobrescritas e as tabelas de páginas foram marcadas, portanto, se o programa tocasse essas páginas novamente, elas seriam paginadas no sistema de arquivos. Os dados foram paginados a partir da troca. Como observado acima, a biblioteca STDIO coletou dados em blocos e foi obtida pelo programa conforme necessário: fgetc, fgets, fread etc. Com o mmap, um arquivo pode ser mapeado no espaço de endereço de um processo, como é feito com o objetos de biblioteca compartilhada ou mesmo arquivos regulares. Sim, você pode ter algum grau de controle se estiver na RAM ou não (mlock), mas isso só vai tão longe (consulte a seção de código de erro do mlock).

Roger L.
fonte
1
A afirmação "sua RAM será muito pequena para seus arquivos" é verdadeira agora, como era nos velhos tempos do VAX.
Federico Poloni
1
@Federico_Poloni Não é tão verdade hoje. No meu último empregador, tínhamos um PC de classe de estação de trabalho com 1 TB de RAM e apenas 0,5 TB de disco rígido. (Classe do problema: entradas pequenas, saídas médias, grandes matrizes acessadas aleatoriamente durante o cálculo).
Nigel222 31/05