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

22

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 no 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 fizerem isso, esses arquivos 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 eu me pergunto é se a vida dupla de um comando, um no disco rígido, o outro na RAM também é verdade para outros tipos de arquivos, por exemplo, aqueles que não têm lógica programada, mas são simplesmente recipientes para dados.

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

Por favor, alguém poderia entender isso?

    
por sharkant 30.05.2017 / 00:07

3 respostas

29

However when commands are being run, a copy of their files from the hard disk is put into the 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 a memória virtual . Observe que os programas aplicativos podem alterar seu espaço de endereço virtual usando mmap (2) & munmap & mprotect (2) , também usado pelo redutor dinâmico (consulte ld -linux (8) . Veja também madvise (2) & posix_fadvise (2) & mlock (2) .

Futuras falhas de página serão processadas pelo kernel para carregar páginas (lazily) do arquivo executável. Leia também sobre se debatendo .

O kernel mantém um grande cache de páginas . Leia também sobre copy-on-write . Veja também readahead (2) .

OK, so what I wonder about is if the double life of a command, one on the hard disk, the other in the RAM is also true for other kind of files, for instance those who have no logic programmed, but are simply containers for data.

Para chamadas de sistema como leia (2) & escreva (2) o cache de páginas também é usado. Se os dados a serem lidos estiverem armazenados, nenhum disco IO será executado. Se o disco IO for necessário, os dados lidos seriam muito provavelmente colocados no cache da página. Então, 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 - você poderá ouvir isso; ou observe atentamente o seu LED do disco rígido).

Eu recomendo ler um livro como Sistemas operacionais: três peças fáceis (disponível gratuitamente para download, um arquivo PDF por capítulo) que explica tudo isso.

Veja também Linux Ate My RAM e execute comandos como xosview , top , htop ou cat /proc/self/maps ou cat /proc/$$/maps (consulte proc (5) ).

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

    
por 30.05.2017 / 02:57
35

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

Com awk é o mesmo. Ele lê um registro por 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

Como o shell terá que expandir a substituição do comando $(cat file) completamente antes de executar o loop for , este irá ler o total de file na memória (aquela do shell executando o for loop). Isso é um pouco bobo. Em vez disso, deve-se fazer

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

Isso processará file linha por linha (mas leia Entendendo "IFS = leia a linha -r ").

O processamento de arquivos linha a linha no shell raramente é necessário, já que a maioria dos utilitários é orientada por linhas de qualquer maneira (veja Por que usar um loop de shell para processar texto é considerado uma prática ruim? ).

Estou trabalhando em bioinformática e, ao processar grandes quantidades de dados genômicos, não seria capaz de fazer muito, a menos que eu apenas mantivesse os bits dos dados que eram absolutamente necessários na memória. Por exemplo, quando preciso remover 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 programa awk simples (isso é possível já que o formato VCF é orientado à linha). Eu não leio o arquivo na memória, o processo lá e o escrevo novamente! Se o arquivo fosse compactado, eu o alimentaria por zcat ou gzip -d -c , que, como gzip faz o processamento de dados em fluxo, também não leu todo o arquivo na memória.

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

Com 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 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 SO na esperança de que o usuário faça muitas referências a eles. Além da primeira leitura do arquivo, os acessos subseqüentes serão feitos na RAM, e não no disco. O armazenamento em cache, como o buffer de entrada e saída, geralmente é amplamente transparente para o usuário e a quantidade de memória usada para armazenar em cache as coisas pode mudar dinamicamente dependendo da quantidade de RAM alocada pelos aplicativos, etc.

1 Tecnicamente, a maioria dos programas provavelmente lê uma parte dos dados de entrada por vez, usando o buffer explícito, ou implicitamente através do buffer que as bibliotecas de E / S padrão fazem, e em seguida, apresente esse pedaço linha por linha para o usuário. É muito mais eficiente ler um múltiplo do tamanho de bloco do disco do que, e. um personagem de cada vez. Esse tamanho de bloco raramente será maior que um punhado de kilobytes.

    
por 30.05.2017 / 00:51
6

Não. Embora ter gigs de RAM hoje em dia seja fantástico, houve um tempo em que a RAM era um recurso muito limitado (aprendi programação em um VAX 11/750 com 2MB de RAM) e a única coisa na RAM eram executáveis e páginas de dados ativas processos e dados do arquivo que estavam no cache do buffer. O cache de buffer foi liberado e as páginas de dados foram trocadas. E freqüentemente às vezes. As páginas executáveis somente para leitura foram escritas em excesso e as tabelas de páginas marcadas, portanto, se o programa tocasse essas páginas novamente, elas seriam paginadas do sistema de arquivos. Os dados foram paginados a partir do swap. Como mencionado 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 objetos de biblioteca compartilhada ou até arquivos regulares. Sim, você pode ter algum grau de controle se estiver na RAM ou não (mlock), mas só vai até certo ponto (veja a seção do código de erro do mlock).

    
por 30.05.2017 / 17:51