%--------------------------------------------------------------------
%%\chapter{Memory Management} \label{chap:mem}
\chapter{Gerenciamento de Memória} \label{chap:mem}
%--------------------------------------------------------------------

        \begin{chapterquote}
	Minnet, jag har tappat mitt minne, \\
	\"ar jag svensk eller finne \\
	kommer inte ih\aa g\dots \\
	(Bosse \"Osterberg) \\
        \end{chapterquote}

	\noindent
	Esta seção descreve as características do gerenciamento de 
	memória do \linux, isto é, a memória virtual e o cache de disco. 
	Os aspectos e considerações que o administrador de sistemas 
	estão descritos neste capítulo.
	
%%\section{What is virtual memory?}
\section{O que é memória virtual?}

	O \linux\ tem suporte a \defin{memória virtual}, isto é, ele utiliza o 
	disco 
	como extensão da memória RAM, fazendo com que o tamanho de memória 
	disponível cresça consideravelmente. O kernel irá gravar o conteúdo de 
	blocos de memória sem uso no disco rígido, podendo aquela área agora ser 
	utilizada para outros propósitos. Quando o
	conteúdo original faz-se necessário, eles são lidos e colocados novamente
	na memória. Isso é feito de maneira totalmente transparente para o
	usuário. Programas sendo executados sob o \linux\ somente vêem a quantidade
	total de memória disponível, sem perceber que partes dela residem no disco
	de tempos em tempos. Obviamente, ler e gravar em disco é muito mais lento 
	(na ordem de 1.000 vezes mais lento) que utilizar memória real, tornando
	portando os programas também mais lentos. A parte do disco que é usada
	como memória virtual é chamada \defin{área de troca} ou 
	\defin{área de swap} (swap space).

	O \linux\ pode usar tanto um arquivo normal de um sistema de arquivos 
	quanto uma partição separada para a área de troca. Uma partição dedicada 
	é mais rápida, porém é mais fácil mudar o tamanho de um arquivo de troca 
	(não há necessidade de reparticionar o disco inteiro, e possivelmente 
	instalar o sistema desde o início). Quando se sabe a quantidade de troca
	necessário, o mais indicado é utilizar uma partição dedicada, mas em caso
	de dúvida, deve-se utilizar um arquivo de troca inicialmente, até que se
	esteja seguro sobre a quantidade necessária. Neste hora é indicada a
	criação de uma partição específica.                

	Cabe salientar que o \linux\ permite a utilização simultânea de diversas 
	partições e arquivos de troca. Isso
	significa que caso seja necessário ocasionalmente uma área de troca maior,
	pode-se criar um arquivo com esta finalidade, ao invés de gerar uma
	partição com todo o espaço necessário.          
	
	Nota sobre termos em sistemas operacionais: a ciência da computação 
	normalmente faz distinção entre troca (gravar todo o conteúdo de um 
	processo em uma área de troca) e paginação (gravar partes fixas da memória, 
	normalmente poucos kilobytes, de cada vez). Paginação é normalmente mais 
	eficiente e é o que o \linux\ faz, mas por tradição a terminologia no 
	\linux\ foi mantida como troca (swap)\footnote{Apesar de deixar algumas
	pessoas horrorizadas!}.


%%\section{Creating a swap space}
\section{Criando uma área de troca}

	Um arquivo de troca é um arquivo comum, sem nenhum
	tratamento especial para o kernel. A única coisa que importa para o kernel
	é que este não possua espaços, e ele foi preparado para uso pelo 
	utilitário \cmd{mkswap}.
	Ele deve residir em um disco local, ainda que possa estar em um sistema de
	arquivos que foi montado via NFS devido à razões de implementação.


	A questão sobre ausência de espaços é importante. O arquivo de troca reserva
	um espaço em disco para que o kernel possa rapidamente trocar uma página sem
	ter que passar por todos os ítens necessários quando da alocação de um setor
	para um arquivo. O kernel simplesmente utiliza qualquer setor que tenha
	sido alocado para o arquivo de troca. Como um espaço vazio no arquivo 
	significa que não há setores de disco alocados (naquele local), não é 
	interessante para o kernel tentar utilizá-lo.   

	Uma boa maneira de criar uma área de troca sem espaços vazios é utilizar 
	o seguinte comando:       
		%
		\begin{tscreen}
\verb|$| {\sl dd if=/dev/zero of=/extra-swap bs=1024 count=1024}\\
\verb|1024+0 registros de entrada| \\
\verb|1024+0 registros de saída| \\
\verb|$|
		\end{tscreen}
		%
	Onde \fn{/extra-swap} é o nome do arquivo de troca e o tamanho é dado pelo
	parâmetro \texttt{count=}. O tamanho mais indicado deve ser múltiplo de 4, 
	uma vez que o kernel utiliza páginas de memória de 4 Kb de tamanho. Caso 
	não seja múltiplo alguns kilobytes não serão utilizados.

	Uma partição de troca também não tem nada de especial. É criada como
	qualquer outra partição, a única diferença é que ela é acessada de maneira
	direta, isto é, não contém nenhum sistema de arquivos. É aconselhável
	marcar a partição de troca como de tipo 82 (\linux\ swap); isso tornará
	claro a listagem das partições, mesmo que não seja necessário para o
	kernel.   

	Após criar a partição de troca ou um arquivo de troca, é
	necessário gravar uma assinatura no seu início, que contém algumas
	informações administrativas utilizadas pelo kernel. O comando utilizado é
	o \cmd{mkswap}, da seguinte forma:  
		%
		\begin{tscreen}
\verb|$| {\sl mkswap /extra-swap 1024} \\
\verb|Setting up swapspace, size = 1044480 bytes| \\
\verb|$|
		\end{tscreen}
		%
	Note que a área de troca ainda não está sendo utilizada; ela existe,
	mas o kernel não a está utilizando como memória virtual.          
	
	Deve-se ser extremamente cuidadoso com o comando \cmd{mkswap}, uma vez 
	que ele não checa se o arquivo ou a partição já está sendo utilizada para 
	outra finalidade. \emph{pode-se facilmente sobrescrever arquivos 
	importantes ou mesmo partições inteiras com o \cmd{mkswap}}. Felizmente 
	este comando é necessário somente durante a instalação do sistema.  

	O gerenciador de memória do \linux\ limita o tamanho da área de troca em
	cerca de 127~Mb (por várias razões técnicas, o limite atual é 
	$(4096-10)\times 8\times 4096 = 133890048$ bytes, ou
	mais precisamente 127.6875~Mb). Pode-se porém utilizar até 16 áreas de troca
	simultaneamente, totalizando cerca de 2~Gb\footnote{Um gigabyte aqui, outro
	ali e estaremos, logo logo, falando de {\em memória de verdade}}.    

%%\section{Using a swap space}
\section{Usando a área de troca}

	Uma área de troca é ativada através do comando \cmd{swapon}. Este comando 
	diz ao kernel que a área de troca pode ser usada. O caminho para a área de 
	troca é dado como um argumento. Para iniciar o processo de troca em um arquivo
	temporário pode-se usar o seguinte comando: 

		%
		\begin{tscreen}
\verb|$| {\sl swapon /extra-swap} \\
\verb|$|
		\end{tscreen}
		%
	Áreas de troca podem ser usadas automaticamente ao serem listadas no
	arquivo \fn{/etc/fstab}:
		%
		\begin{tscreen}
\verb|/dev/hda8        none        swap        sw     0     0| \\
\verb|/swapfile        none        swap        sw     0     0|
		\end{tscreen}
		%
	O script de inicialização \fn{/etc/rc.d/rc.sysinit} executará o comando 
	\texttt{swapon -a}, inicializando as áreas de troca listadas no arquivo 
	\fn{/etc/fstab}. O \cmd{swapon} é ainda usado para se adicionar
	novas áreas de troca, sem precisar reinicializar o sistema.

	Pode-se monitorar o uso das áreas de troca através do comando \cmd{free}. 
	Ele apresentará o total de troca disponível:    
		%
		\begin{tscreen}
\verb|$| {\sl free} \\
\verb|             total       used       free     shared    buffers     cached| \\
\verb|Mem:         63140      60328       2812      32528       5248      18020| \\
\verb|-/+ buffers/cache:      37060      26080| \\
\verb|Swap:       104384      15288      89096| \\
\verb|$|
		\end{tscreen}
		%
	O primeiro item da saída (\verb|Mem:|) mostra a memória física. 
	A coluna de total não apresenta a memória física usada pelo kernel, a qual 
	gira em torno de um megabyte. A coluna {\em used} apresenta a memória 
	utilizada. A coluna de memória livre mostra a quantidade de memória sem 
	uso. A coluna de memória compartilhada mostra a memória utilizada por 
	diversos processos; quanto mais, melhor. A coluna de buffers apresenta 
	o tamanho atual do buffer cache de disco.         
	%% buffer cache ???
	
	A última linha (\verb|Swap:|) mostra informações similares sobre a área de 
	troca. Se todos os dados desta linha estiverem zerados, sua área de troca
	não está ativada.

	As mesmas informações podem ser obtidas através do comando \cmd{top} ou 
	através do arquivo \fn{/proc/meminfo} no sistema de arquivos \fn{/proc}.  
	                                         

	Uma área de troca pode ser desativada através do comando \cmd{swapoff}. 
	Normalmente isso não é necessário, exceto para áreas temporárias. 
	Qualquer página em uso na área será devolvida à memória primeiro, e caso 
	não haja memória física disponível para manter todas as páginas, o \linux\ 
	começará a ter problemas e não conseguirá executar diversos comandos; após 
	um período ele pode se recuperar, mas neste meio tempo estará
	indisponível. Deve-se checar, com o comando \cmd{free}, se há
	memória livre suficiente para remover a área de troca em uso.  


	Todas as áreas de troca que são usadas automaticamente através do comando 
	\texttt{swapon -a} podem ser removidas pelo comando \texttt{swapoff -a}; 
	ele verifica o conteúdo do arquivo \fn{/etc/fstab} para descobrir o que 
	deve ser removido. As áreas de troca ativadas manualmente permanecerão 
	em uso.  

	Algumas vezes uma grande quantidade de área de troca pode estar em uso, 
	apesar de existir uma grande quantidade de memória física livre. Isso 
	pode ocorrer por exemplo
	quando em determinado momento há necessidade de efetuar uma troca,
	porém logo após um processo que ocupava muita memória física foi
	concluído, liberando a memória física em uso. Os dados que foram gravados
	na área de troca não são automaticamente retornados para a memória física
	até que isso seja necessário, podendo a memória física ficar um longo
	tempo sem uso. Não há com o que se preocupar em relação a esta situação,
	porém é bom saber o que está ocorrendo.

%%\section{Sharing swap spaces with other operating systems}
\section{Compartilhando áreas de troca com outros sistemas operacionais}

	Memória virtual é uma funcionalidade disponível em diversos sistemas
	operacionais. Uma vez que cada sistema somente a utiliza quando estiver
	rodando, ou seja, nunca ao mesmo tempo, pois não é possível executar mais
	de um sistema ao mesmo tempo, uma idéia mais eficiente seria compartilhar
	uma única área de troca. Isso é possível, mas requer um conhecimento
	avançado. O Tips-HOWTO (veja o Apêndice~\ref{tips}) contém algumas 
	orientações sobre a forma de implementar isto.  

%%\section{Allocating swap space} \label{sec:swap-alloc}
\section{Alocando áreas de troca} \label{sec:swap-alloc}

	Algumas pessoas dirão que se deve alocar o dobro da memória física 
	para a área de troca, mas esta é uma regra simplista. 
	Seguem sugestões de como se fazer isto corretamente:

    \begin{enumerate}

    \item

	Estime o total de memória necessária. Esta é a maior quantidade de memória 
	que você provavelmente irá precisar em um determinado momento, ou seja, a 
	soma dos requisitos de memória de todos os programas que podem rodar
	simultaneamente. Isso pode ser feito rodando-se todos os programas
	passíveis de execução ao mesmo tempo em seu sistema.  

	Por exemplo, caso se deseje executar o X, deve-se alocar no mínimo 8~Mb 
	para ele, o gcc usa muitos megabytes (alguns arquivos necessitam grandes 
	quantidades de memória, até dezenas de megabytes, mas normalmente ao redor 
	de 4 Mb deve ser suficiente, e assim por diante. O kernel utiliza em torno
	de 1 Mb por si só, e o interpretador de comandos padrão e outros pequenos 
	utilitários usam alguns poucos kilobytes (digamos 1~Mb se somados). 
	Não há necessidade de ser exato, estimativas aproximadas são suficientes, 
	mas neste caso deve-se sempre estimar pelo máximo.
	

	Lembre-se que se há diversos usuários utilizando o sistema ao mesmo tempo, 
	todos eles irão consumir memória. Porém, caso duas pessoas executem o
	mesmo programa ao mesmo tempo, o total de memória consumido não será o 
	dobro,  pois as páginas de código e bibliotecas compartilhadas existem em 
	somente uma instância. Os comandos \cmd{free} e \cmd{ps} são muito úteis 
	para estimar a memória necessária.
	
    \item
	Adicione uma margem de segurança à estimativa do passo 1. Isso porque
	as estimativas do tamanho dos programas estará provavelmente errada. 
	Certamente há outros programas que serão necessários e provavelmente não
	foram lembrados. Também é bom ter-se uma certa margem de segurança. Alguns
	megabytes devem atender (é melhor alocar uma área de troca maior do que
	uma área muito pequena, mas também não há necessidade de se alocar o disco 
	inteiro, afinal, a área de troca é um espaço perdido, caso não utilizada.
	Como é melhor trabalhar com números inteiros, pode-se arredondar o valor 
	para o próximo megabyte.    
	
    \item
	Baseado nos cálculos acima, você irá descobrir quanta memória será 
	necessária no total. Então, para alocar a área de troca, basta somente 
	subtrair o tamanho da memória física do total de memória necessária; assim 
	obtem-se o tamanho necessário para a área de troca (em alguns sistemas 
	\unix\ é necessário alocar espaço para uma imagem da memória física. 
	Neste caso o valor encontrado no passo 2 é o valor necessário para a área 
	de troca).       

    \item
	Caso a área de troca seja muito maior que a memória física (algumas vezes
	maior), será necessário  aumentar o total de memória física instalada, 
	pois de outra forma a performance será razoável.   

    \end{enumerate}
    
	É aconselhável ter ao menos alguma área de troca, mesmo que os cálculo
	indiquem que nenhuma área é necessária. O \linux\ usa a área de troca de 
	forma agressiva, desta maneira o máximo possível de memória física pode 
	permanecer livre. O \linux\ irá transferir para a área de troca as páginas 
	de memória que
	não estejam sendo utilizadas, mesmo que a memória física não esteja sendo
	requisitada para outra tarefa. Isso evita esperas quando a memória for
	necessária --- a troca pode ser feita mais cedo, quando o disco está
	disponível.    

	A área de troca pode ser dividida em diversos discos. Isso
	pode eventualmente aumentar a performance, dependendo da velocidade
	relativa dos discos e do tipo de acesso aos mesmos. Pode-se experimentar
	algumas formas, mas é importante salientar que as experiências podem ser
	bastante complexas. Não se deve crer que uma maneira é superior a outra
	pois nem sempre isso será verdade.

%%\section{The buffer cache}
\section{O cache}
\label{sec:buffer-cache}

	A leitura do disco\footnote{Exceto a RAM disk, por razões óbvias} é muito 
	lenta quando comparada com o acesso a memória real. Adicionalmente, é 
	comum ler-se a mesma parte do disco diversas vezes durante um período de 
	tempo relativamente curto. Por exemplo, alguém pode primeiro ler um email, 
	depois responde-lo em um editor e finalmente salvar o mail em uma pasta
	para arquivamento.
	Ou então considere quão freqüentemente o comando \cmd{ls} é executado em um
	sistema com diversos usuários. Ao ler as informações do disco e
	armazenando-os em memória até que não seja mais necessário, pode-se agilizar
	todos os acessos posteriores ao primeiro. Isso é chamado de 
	\defin{buffering de disco}, e a memória usada para este fim é chamada de 
	\defin{buffer cache}.      

	Uma vez que a memória é, infelizmente, um recurso escasso, o
	buffer cache não pode ser muito grande. Ele pode não conter 
	todos os dados que os programas necessitem. Quando o cache está cheio, os 
	dados sem uso há mais tempo são descartados e a memória é então liberada 
	para uso por dados novos.

	Buffering de disco funciona também para gravação.
	Por um lado, dados que são gravados são também lidos com muita
	0 (por exemplo o código fonte de um programa, primeiro é salvo em 
	um arquivo, e depois é lido pelo compilador), então, colocar os dados 
	gravados em um cache é também uma boa idéia. Por outro lado, colocar os 
	dados a serem gravados somente em memória, sem gravá-los efetivamente em 
	disco, agiliza o programa que deveria gravá-los. A gravação pode então ser 
	feita em segundo plano, sem diminuir a velocidade de gravação dos outros 
	programas.  

	Muitos sistemas operacionais têm cache de buffer (apesar de às vezes
	receber outro nome), mas nem todos funcionam dentro dos mesmos princípios.
	Alguns são chamados \defin{write-through}\footnote{de \defin{gravação imediata}}: os dados são gravados no disco
	imediatamente (e são mantidos no cache obviamente), outros são chamados
	\defin{write-back}\footnote{de \defin{gravação posterior}}, isto é, a 
	gravação somente é feita após intervalos de tempo.
	O write-back é mais eficiente, mas mais suscetível a erros: caso uma
	máquina tenha algum problema, ou a energia elétrica for cortada em um mau
	momento, ou o disquete for removido sem ser desmontado, as mudanças
	registradas no cache são perdidas. Isso pode significar que o sistema de
	arquivos pode não funcionar bem, talvez devido a dados não gravados que
	continham informações críticas à atualização do sistema de arquivos.            

	Por causa disso,
	nunca deve-se desligar um equipamento sem seguir os procedimentos
	adequados (veja o capítulo~\ref{ch:boothalt}), ou remover um disquete da 
	unidade sem que o dispositivo esteja desmontado.  O comando
	\cmd{sync} esvazia o buffer, isto é, força a gravação de dados ainda não
	atualizados, podendo ser utilizado quando se quer ter certeza que tudo está
	em segurança e atualizado. Em sistemas \unix\ tradicionais, há um programa
	chamado \cmd{update} que roda em segundo plano, executando um \cmd{sync}
	a cada 30~segundos. O \linux\ tem ainda um outro programa chamado
	\cmd{bdflush}, o qual executa uma sincronização imperfeita mais 
	0 para evitar travamentos súbitos devido ao grande tráfego 
	de entrada e saída que o \cmd{sync} pode, ocasionalmente, gerar.
	

	No \linux, o \cmd{bdflush} é ativado pelo \cmd{update}. Não há razão para 
	preocupar-se com isso, mas se o \cmd{bdflush} morrer por alguma razão, o 
	kernel emitirá um aviso sobre a ocorrência e ele deverá ser reinicializado 
	executando-se o \cmd{/sbin/update}.

	O cache não põe arquivos no buffer, mas sim blocos, que são as menores
	unidades de E/S (no \linux, eles tem normalmente 1~Kb). Dessa
	forma diretórios, superblocos, outros sistemas de arquivos e discos sem
	sistemas de arquivos são armazenados no cache.


	A eficiência do cache é definida basicamente pelo seu tamanho. Um cache
	pequeno é quase inútil:  ele manterá poucos dados e toda a informação 
	será retirada do cache antes de ser usada novamente. O tamanho
	correto depende do volume de dados que é lido e gravado simultaneamente e 
	qual a freqüência que o mesmo dado é acessado. A única forma de saber é 
	experimentando.  
	
	Caso o cache tenha um tamanho fixo, é melhor não defini-lo com um tamanho 
	muito grande, pois isso pode diminuir demasiadamente a memória livre 
	e causar um volume excessivo de troca (e consequentemente deixar o 
	sistema mais lento). 
	Para tornar mais eficiente o uso da memória real, o \linux\ automaticamente 
	usa toda a memória livre como cache de buffer, mas também o diminui quando 
	os programas necessitam de mais memória. 
	
	No \linux, você não precisa fazer nada para utilizar o cache, tudo acontece
	automaticamente. Exceto por seguir os procedimentos de desligamento e
	remoção de disquetes, não há com o que se preocupar.  
