Gerenciamento (ou gestão) de memória é um complexo campo da ciência da computação e são constantemente desenvolvidas várias técnicas para torná-la mais eficiente. Em sua forma mais simples, está relacionado em duas tarefas essenciais: Alocação: Quando o programa requisita um bloco de memória, o gerenciador o disponibiliza para a alocação; Reciclagem: Quando um bloco de memória foi alocado, mas os dados não foram requisitados por um determinado número de ciclos ou não há nenhum tipo de referência a este bloco pelo programa, esse bloco é liberado e pode ser reutilizado para outra requisição.

Gerência de Memória A cada dia que passa os programadores necessitam de mais memória e mais programas rodando simultaneamente para poderem tratar cada vez mais informações. O tratamento necessário da memória utilizada não é uma tarefa fácil de ser implementada. Existem vários requisitos que devem ser observados para o correto funcionamento, tais como, segurança, isolamento, performance, entre outros. Para isto a função de gerenciar a memória passa a ser do sistema operacional e não mais do aplicativo.

Para que uma memória funcione de maneira correta, é necessário que se tome cuidado com vários elementos como segurança e isolamento, e para isso é utilizado o gerenciamento de memória. Este desenvolve sua função a partir de duas tarefas, a Alocação de Memória e a Fragmentação: A Alocação pode ser tanto estática, feita quando o programa é compilado, e a dinâmica, adiada até a execução. A Fragmentação, desperdício de memória, por sua vez pode ser interna, sobra na memória reservada ao programa, e externa que acontece quando após o termino dos programas são deixadas pequenas lacunas entre as páginas. Para que a utilização da memória seja mais vantajosa, é utilizada a Paginação, processos virtuais da memória, aplicados na divisão da memória física em partições menores, chamadas de frames.

O conjunto de registradores especiais rápidos chama-se Translation Lookaside Buffer, estes são subdivididos em chave valor que lhe é dado em todos os registradores ao mesmo tempo, e valor.

Existe uma técnica de gerencia de memória chamada memória virtual, que é onde memórias principais e secundárias juntas criam a ilusão de que há muito mais memória. O conceito desta técnica fundamenta-se em não vincular o endereçamento feito pelo programa aos endereços físicos da memória principal, com isso os programas e suas estruturas de dados não se limitam ao tamanho da memória física, e assumem endereços na memória secundária. O gerenciamento de memória virtual pode ocasionar vazamento de memória, ou seja, quando determinada quantia de memória é alocada e não é liberada mesmo que não sendo utilizada, assim dados perdem a referencia sem ao menos terem usado memória.

O gerenciamento automático chama-se Garbage collector. Ele retira os blocos de memória automaticamente. Seus algoritmos são divididos em duas famílias: a Identificação direta, por contagem de referência, e a Identificação indireta, por varrimento.

Alocação de Memória Todo programa precisa utilizar memória para ser executado. Quando um programa inicia sua execução, ele começa a solicitar memória ao sistema operacional, ou seja, faz a alocação de memória necessária para a sua execução. A alocação de memória está dividida em 3(três) partes:

Alocação Estática: Decisão tomada quando o programa é compilado. Quando o programa é executado o Sistema operacional o lê e cria um processo, sendo o programa uma noção estática e o processo o programa em execução, que é criado em armazenamento primário e após isso recebe um espaço na memória. O espaço de memória é dividido em varias partes, uma das partes se chama segmentos de memória, que armazena dados estáticos, e outro se chama segmento de código que guarda instruções do programa. Quando o programa é executado o registrador PC apontará para determinado endereço do segmento de código do processo, que se chama TEXT. Para que se realize a alocação estática o compilador deve saber o total de memória que está livre, mandar esta informação para o S.O para que este crie um segmento de dados. Alocação Dinâmica: Decisão é adiada até a execução. (Permite Swapping) Os objetos alocados dinamicamente podem ser criados e liberados a qualquer momento, em qualquer ordem, o que difere dos objetos locais das funções, que são criados e destruídos em uma ordem específica. Dado isto, é preciso organizar a memória para objetos dinâmicos de uma forma que possibilite a gestão do tempo de vida dos objetos por parte do programador. A memória reservada para objetos dinâmica costuma ser chamada de heap, existem várias formas de organizar um heap. Em linguagens sem a gestão automático (linguagem C), da memória dinâmica, uma organização usual do heap é uma lista encadeada de blocos livres, porém este tipo de organização pode ter problemas devido à fragmentação dos blocos. Já em linguagens com gerenciamento automático de memória dinâmica (Java), a organização do heap depende da parte do sistema de tempo de execução encarregada desta gestão. Este componente é normalmente chamado de coletor de lixo. Alguns tópicos para podermos entender melhor: • Carrega vários processos na memória ao mesmo tempo; • Quando chega um novo processo, e a memória principal está toda ocupada, escolhe um processo, grava-o no disco, e libera memória para o próximo. Alocação Local: Este processo de alocação é usado para variáveis que são locais a funções e sub-rotinas. Isso significa que o processo em execução deve manter acessível as variáveis locais da função ou procedimento que está executando no momento. Além disso, pelas propriedades do escopo em blocos, também devem estar acessíveis as variáveis de blocos mais externos. Em linguagens que permitem a definição de funções aninhadas, ter acesso a variáveis de quaisquer funções definidas externamente à função atualmente em execução. Como uma função pode chamar outras funções, um número arbitrário de funções pode estar no meio de sua execução em um determinado momento, mesmo que apenas uma esteja realmente sendo executada, isso indica que o contexto de várias funções deve ser mantido enquanto as mesmas não concluíram sua execução.

Fragmentação Em computação, significa o desperdício de espaço disponível em memória.

Pode ser de dois tipos: Interna: Ocorre quando o processo não ocupa inteiramente os blocos de memória (páginas) reservados para ele. Geralmente acontece pois o tamanho do processo não é um múltiplo do tamanho da página de memória, o que acarreta sobra de espaço na última página alocada. (dentro de um processo)

Externa: Ocorre à medida que os programas vão terminando e deixando lacunas cada vez menores de espaços entre as páginas. Dependendo do tamanho que precisa ser escrito em memória, estes espaços podem ser pequenos demais para serem úteis, e assim ficam inutilizados. (entre processos) Estratégias para "atacar" o problema com o algoritmos First-fit, Best-fit, Worst-fit e Next-fit.

Paginação No contexto dos sistemas operacionais, a paginação da memória do computador é um processo de virtualização da memória que consiste na subdivisão da memória física em pequenas partições (frames), para permitir uma utilização mais eficiente da mesma. A alocação de memória é requisitada por páginas, a menor unidade deste método. Cada página é mapeada num frame de memória através de um processo chamado de paginação. O sistema operacional pode estar em base do espaço de endereçamento, em RAM, ou estar no topo do espaço de endereçamento, em ROM, e o restante do sistema mais embaixo, em RAM. O primeiro modelo foi inicialmente empregado em computadores de grande porte e mini-computadores (mas não é muito usado). O segundo modelo é utilizado em alguns computadores de mão e em sistemas embarcados. O terceiro modelo fez parte dos primeiros computadores pessoais, nos quais a parte do sistema contida em ROM é denominada BIOS. Quando o sistema é organizado dessa maneira, somente um processo pode ser executado a cada instante. Tão logo um usuário tecle um comando, o sistema operacional carrega o programa solicitado, do disco, para a memória e o executa. Quando o processo finaliza, o SO coloca na tela um caractere de prompt e espera por um novo comando. Ao receber um novo comando, carregará o novo programa na memória, no espaço de endereçamento ocupado pelo programa anterior.

Translation Lookaside Buffer

A Translation Lookaside Buffer (TLB) é um conjunto de registradores especiais que são bastante rápidos. Ela está presente na Unidade de Gerenciamento de Memória de uma processador. Cada registrador tem duas partes: chave e valor. Dada uma chave, busca-se o valor correspondente. Geralmente o número de entradas não passa de 256TANENBAUM, Andrew S. Sistemas operacionais modernos. Cap. 3. Rio de Janeiro: LTC. 1999. e a busca é feita em todos os registradores simultaneamente.

Algoritmos de Substituição de Página

Algoritmo Ótimo Algoritmo Não Usada Recentemente Algoritmo FIFO Algoritmo Segunda Chance Algoritmo do relógio Menos Recentemente Usada WSClock

Em modelos de gerenciamento manual, podem ocorrer os problemas conhecidos como vazamento de memória, que acontece quando uma quantidade de memória é alocada e não é liberada ainda que nunca seja utilizada. Isto ocorre quando objetos perdem a referência sem terem sido liberados, mantendo o uso do espaço de memória.

Garbage Collector É o gerenciamento automático de memória, também conhecido como coletores, sendo conhecido em Portugal como reciclagem automática de memória. Este serviço libera os blocos de memória que não sejam mais usados por um programa automaticamente. É oposto ao gerenciamento de memória manual, a alocação explicita e a desalocação dos recursos de memória do computador.

As vantagens desse tipo de gerenciamento são:

Liberdade do programador: Não é obrigado ficar atento aos detalhes da memória; Menos bugs de gerenciamento de memória: Por se tratar de uma técnica mais confiável; Gerenciamento automático: Mais eficiente que o manual.

E entre as desvantagens, podemos citar:

O desenvolvedor tende a estar mais desatento em relação a detalhes de memória; O gerenciador automático ainda apresenta limitações.

Quando deixam de existir referências a um objeto, este passa a ser considerado apto a ser "coletado" pelo garbage collector, que significa dizer que será removido da memória, deixando-a livre para uso por outros objetos.

Os algoritmos de garbage collection operam de um modo que permite classificá-los em duas grandes famílias:

Identificação Direta: por contagem de referências (reference counting); Identificação Indireta: por varrimento (tracing), que pode incluir também compactação da memória livre; cópia; ou geracional (utilizado nas máquinas virtuais Java e .NET).

Gerenciamento de memória no DOS O IBM PC original foi projetado com uma memória RAM de 1024KB 640KB Para o sistema operacional e programas 384KB - área de memória superior (Upper Memory Area) ou UMA Para os adaptadores diversos como EGA & VGA, MDA, adaptadores CGA, e de redes. ROM BIOS e Shadow RAM. E mais tarde, área de paginação de expansão de memória (EMS) vista mais adiante.

Logo depois, foi provado que esta quantidade de memória se tornaria insuficiente para as necessidades futuras.

Entretanto, os sistemas operacionais e aplicativos desenvolvidos até então não seriam capazes de reconhecer um endereço de memória superior aos 640KB originais, o que levou os projetistas a desenvolverem ferramentas que executariam esta tarefa.

Emm386.exe É o dispositivo de instalação da memória expandida (Expanded Memory) ou EMS. A EMS consistia em toda a memória acima dos 1024KB (1MB) original, em computadores baseados nas tecnologias dos processadores 80286, 80386, i486 ou Pentium.