Espaços de Endereçamento e Tradução de Endereços

Aprenda como um sistema operacional fornece a cada programa em execução uma memória própria e protegida. Comece pelo espaço de endereçamento que um programa vê e pelos objetivos da virtualização de memória. Depois, acompanhe as requisições à área de alocação dinâmica feitas por malloc e free até as chamadas de sistema que as sustentam. Traduza endereços passo a passo com registradores base e limite e com segmentação, e veja como gerenciadores de espaço livre alocam requisições de tamanhos variados, do primeiro ajuste à alocação de blocos parceiros, mantendo sob controle a fragmentação interna e externa.

IntermediárioAula 3 de 9 do curso Curso de Sistemas operacionais

O que você vai aprender

  1. Descreva o espaço de endereçamento que um programa em execução vê, por que o sistema operacional virtualiza a memória e os objetivos que todo esquema de virtualização de memória deve atender.
    • Descreva um espaço de endereçamento e sua organização
      Explique o que é um espaço de endereçamento, como código, área de alocação dinâmica e pilha são organizados nele e como os endereços virtuais diferem dos físicos.
    • Avalie a virtualização de memória segundo seus objetivos
      Avalie um esquema de virtualização de memória por sua transparência, eficiência e proteção e diferencie o mecanismo de hardware das políticas do sistema operacional.
  2. Diferencie a memória da pilha da memória da área de alocação dinâmica, requisite e libere memória dessa área com as chamadas padrão, reconheça os erros que elas podem causar e explique de onde vem a memória que as sustenta.
    • Aloque e libere memória com a API de memória
      Diferencie a memória automática da pilha da memória da área de alocação dinâmica, compreenda o uso correto de malloc e free e reconheça os principais tipos de erros de memória.
    • Explique como o alocador obtém memória do sistema operacional
      Diferencie a função do sistema operacional de gerenciar o espaço de endereçamento de um processo da função da biblioteca de gerenciar a área de alocação dinâmica e descreva as chamadas de sistema que aumentam e reduzem a memória.
  3. Explique como a relocação dinâmica baseada em hardware transforma cada endereço virtual em um endereço físico, o que o hardware e o sistema operacional fazem e quais são as limitações dessa abordagem.
    • Traduza endereços virtuais com registradores base e limite
      Aplique a relocação dinâmica somando a base a cada endereço virtual e verificando-o em relação ao limite, e compare-a com a relocação estática.
    • Divida o trabalho entre o hardware e o sistema operacional
      Liste o que o hardware deve fornecer e o que o sistema operacional deve fazer na criação de processos, nas trocas de contexto, nas exceções e no encerramento para que base e limite funcione.
    • Avalie o mecanismo de base e limite
      Compare a velocidade e a proteção de base e limite com a memória que ele desperdiça e explique por que esse mecanismo leva à segmentação.
  4. Atribua a cada segmento lógico de um espaço de endereçamento sua própria base e seu próprio limite, traduza e verifique endereços com registradores de segmento e avalie o que a segmentação exige do sistema operacional.
    • Traduza endereços segmento por segmento
      Posicione código, área de alocação dinâmica e pilha de forma independente na memória física e traduza um endereço calculando seu deslocamento dentro do segmento.
    • Identifique o segmento ao qual um endereço se refere
      Determine o segmento pelos bits mais altos de um endereço virtual ou pela forma como o endereço foi formado e calcule o deslocamento em binário.
    • Gerencie a pilha, a proteção e o compartilhamento
      Traduza endereços da pilha com um deslocamento negativo, use bits de proteção por segmento e explique como os processos compartilham código com segurança.
    • Implemente o suporte à segmentação e avalie esse mecanismo
      Descreva o que o sistema operacional deve fazer para oferecer suporte à segmentação, compare a segmentação de granularidade grossa e fina e explique a fragmentação externa que a limita.
  5. Explique como um gerenciador de espaço livre controla a memória livre e atende a requisições de tamanhos variados, compare estratégias de alocação e analise a fragmentação interna e externa.
    • Diferencie fragmentação interna e externa
      Defina os dois tipos de fragmentação, identifique-os em exemplos e explique por que um alocador da área de alocação dinâmica não pode compactar a memória.
    • Controle o espaço livre com uma lista de blocos livres
      Divida e una blocos livres, use cabeçalhos para liberar memória sem informar o tamanho e construa a lista de blocos livres dentro da própria memória livre.
    • Compare estratégias de alocação
      Aplique melhor, pior, primeiro e próximo ajuste a uma lista de blocos livres e compare sua velocidade com a fragmentação que causam.
    • Use listas segregadas, alocação slab e alocação de blocos parceiros
      Explique como listas por tamanho, caches de objetos e blocos parceiros com tamanhos em potências de dois aceleram a alocação e calcule o desperdício e a união de blocos na alocação de blocos parceiros.

Guia de estudo de Tradução de endereços

5 capítulos

1

Uma visão privada da memória para cada processo

Um ponteiro pertence ao processo que o usa. Seu número, por si só, não identifica uma célula de memória física. Os espaços de endereçamento permitem que vários programas permaneçam na memória enquanto cada um executa com sua própria visão de código e dados. O sistema operacional e o processador devem preservar essa visão, traduzir os acessos rapidamente e impedir que um programa danifique outro. Esses objetivos explicam tanto a organização que um programa vê quanto os mecanismos que ficam ocultos por trás dela.

1.1 A memória que um processo vê

Um programa em execução trabalha com um espaço de endereçamento: sua própria visão da memória, com posições de bytes numeradas. O sistema operacional posiciona a memória do programa na máquina e garante que seus endereços alcancem os bytes físicos corretos. A organização que o programa vê e a organização no hardware são coisas diferentes.

Por que vários programas permanecem na memória

Os primeiros sistemas podiam manter um programa ao lado do sistema operacional. Por exemplo, o sistema operacional poderia ocupar os primeiros 64 KB e o programa, a memória restante. A multiprogramação mantinha mais de um processo pronto, para que a CPU pudesse trabalhar enquanto outro processo aguardava entrada ou saída. O compartilhamento de tempo alternava a CPU com frequência suficiente para atender usuários interativos.

Salvar toda a memória de um processo em disco a cada troca tornaria a troca lenta demais. Manter vários processos na memória física evita essa cópia, mas cria um problema de proteção. Um endereço gerado por um processo não deve permitir que ele sobrescreva o sistema operacional ou um processo vizinho.

Os tamanhos de memória aqui seguem a convenção binária usada nesses modelos: 1 KB corresponde a 1.024 bytes, também representado por 1 KiB; 1 MB corresponde a 1.024 KB. Um espaço de endereçamento de 16 KB tem 16.384 posições de bytes, numeradas de 0 a 16.383. O número 16.384 é o limite final, não um endereço de byte válido.

Código, dados, área de alocação dinâmica e pilha
RegiãoO que contémComo é usada
CódigoInstruções de máquinaA CPU busca instruções aqui.
Dados estáticosVariáveis globais e locais estáticasO armazenamento dura toda a execução do programa.
Área de alocação dinâmicaBlocos requisitados durante a execuçãoO programa requisita e libera blocos.
PilhaEstado das chamadas de função e variáveis locais comunsChamadas criam quadros; retornos os liberam.

Em uma organização didática clássica de 16 KB, o código usa os endereços baixos, de 0 até o limite de 1 KB. A área de alocação dinâmica começa acima do código e cresce para cima. A pilha começa no limite superior e cresce para baixo. O espaço livre entre elas permite que ambas cresçam. Organizações reais variam; por exemplo, cada thread tem sua própria pilha. As funções das regiões continuam úteis mesmo quando suas posições mudam.

Acompanhe um ponteiro até a memória correta

Um endereço virtual identifica um byte no espaço de endereçamento de um processo. Um endereço físico identifica um byte no hardware de memória da máquina. Quando um código C imprime printf("%p", (void *) &x), ele imprime um endereço virtual. O ponteiro impresso não revela o byte físico que armazena x.

Suponha que dois processos usem o endereço virtual 1.000. Cada endereço é interpretado no espaço de endereçamento do próprio processo, de modo que os acessos podem alcançar bytes físicos diferentes. Da mesma forma, o código no endereço virtual 0 não precisa ocupar o endereço físico 0. O sistema operacional pode colocá-lo em outro lugar e configurar a tradução por hardware para alcançá-lo.

O processador traduz buscas de instrução, leituras e escritas. O sistema operacional escolhe e gerencia os mapeamentos, inclusive alterando as localizações físicas enquanto mantém estáveis os endereços virtuais do programa.

Principais conclusões

  • Um espaço de endereçamento é a visão que um processo tem da memória, não sua localização física.
  • Código, dados estáticos, área de alocação dinâmica e pilha cumprem funções diferentes de armazenamento.
  • Endereços virtuais são interpretados dentro de um processo; valores iguais podem alcançar bytes físicos diferentes.
  • Um espaço de endereçamento de 16 KB tem bytes de 0 a 16.383 segundo a convenção binária de KB.

1.2 Transparência, eficiência e proteção

Um sistema de memória deve fazer mais do que traduzir corretamente um número. Ele deve permitir que programas comuns executem sem gerenciar a localização física, manter baixo o custo da tradução e impor os limites que tornam o compartilhamento seguro. Esses requisitos são transparência, eficiência e proteção.

Preserve a visão do programa

Transparência significa que um programa executa como se tivesse memória privada. Ele usa seus próprios endereços para código e dados sem acompanhar quais outros processos estão presentes ou onde seus bytes estão. O sistema operacional e o hardware preservam essa visão nos bastidores. Mover um processo na memória física não deve exigir que ele reescreva seus ponteiros.

A ilusão não exige uma cópia física distinta de cada byte para cada processo. Por exemplo, código protegido somente de leitura pode ser compartilhado. O que importa é que o compartilhamento preserve o comportamento e os direitos de acesso aos quais cada processo tem direito.

Considere os dois tipos de custo

Toda busca de instrução, leitura e escrita precisa de tradução. Executar uma rotina do sistema operacional para cada acesso tornaria a execução comum lenta demais. O hardware realiza as operações frequentes; o código do sistema operacional cuida da configuração, das alterações e das falhas.

A eficiência de espaço também importa. Um mecanismo de tradução pequeno e rápido ainda pode desperdiçar muita memória. Uma única região de base e limite reserva o espaço não usado entre a área de alocação dinâmica e a pilha. A segmentação evita reservar memória física para esse espaço, mas introduz regiões físicas de tamanhos variáveis e lacunas entre elas. Metadados, espaço reservado não usado e lacunas afetam a quantidade de trabalho útil que cabe na memória.

ObjetivoPergunta a fazer
TransparênciaO programa continua usando seus próprios endereços sem gerenciar a localização?
Eficiência de tempoQuanto trabalho cada acesso à memória acrescenta?
Eficiência de espaçoQuanta memória é consumida por metadados ou espaço inutilizável?
ProteçãoO processo consegue acessar apenas as regiões e operações que tem permissão para usar?
Faça um acesso inválido parar no limite

Sem proteção, um ponteiro incorreto em um editor de texto poderia sobrescrever outro processo ou o núcleo. O dano poderia aparecer muito mais tarde em um código sem relação com o editor. Com limites impostos, o hardware rejeita um acesso fora da região permitida e gera uma exceção. O sistema operacional trata a exceção e geralmente encerra o processo com defeito, informando comumente uma falha de segmentação.

A proteção isola os processos uns dos outros. Ela não torna seguro o uso da memória em C dentro de uma região permitida da área de alocação dinâmica. Uma escrita além de um bloco alocado ainda pode atingir outro bloco pertencente ao mesmo processo. Limites de processos e limites de blocos do alocador são limites diferentes.

Separe a operação da escolha

Um mecanismo é como uma operação é realizada. Somar um registrador base e verificar um registrador limite são mecanismos. Uma política escolhe entre ações possíveis: onde colocar um processo, qual lacuna livre usar ou quando mover um segmento.

Manter os dois separados permite que o sistema operacional altere sua estratégia de alocação mantendo a mesma tradução por hardware. A virtualização de memória começa com essa visão privada e protegida; ela não é definida pelo uso do disco como memória adicional.

Principais conclusões

  • A transparência preserva a visão do programa quando a localização física muda.
  • A eficiência de tempo importa em cada acesso à memória; a eficiência de espaço inclui regiões não usadas e metadados.
  • A proteção isola processos, mas não impõe todos os limites dos blocos da área de alocação dinâmica.
  • Mecanismos realizam operações; políticas escolhem entre alternativas.
  • O hardware traduz acessos comuns; o sistema operacional gerencia a tradução e trata falhas.
2

Das alocações em C às regiões do sistema operacional

Uma requisição à área de alocação dinâmica atravessa duas camadas de gerenciamento de memória. A biblioteca C encontra um bloco para o programa, enquanto o sistema operacional fornece e protege as regiões das quais os blocos são obtidos. Acompanhar essas camadas explica por que uma variável ponteiro e sua alocação têm tempos de vida diferentes, por que liberar um bloco pode deixar inalterado o uso de memória do processo e por que uma compilação bem-sucedida pouco diz sobre a validade dos acessos posteriores à área de alocação dinâmica.

2.1 Requisição de blocos e respeito aos seus tempos de vida

Uma variável ponteiro e a memória para a qual ela aponta são objetos separados. Entender seus tempos de vida é o ponto de partida para a API de memória de C. Variáveis locais comuns geralmente usam armazenamento automático na pilha, blocos da área de alocação dinâmica duram até serem liberados, e variáveis globais e locais static têm armazenamento durante toda a execução do programa.

Acompanhe a alocação, não apenas o ponteiro
void f(void) {
    int x;
    int *p = malloc(sizeof(int));
}

Na organização usual da pilha, x e p pertencem a essa chamada de f. O inteiro requisitado pertence à área de alocação dinâmica. O retorno remove a variável ponteiro local; ele não libera o bloco da área de alocação dinâmica. Se nenhuma cópia do endereço permanecer, o programa terá perdido acesso a uma alocação ativa: um vazamento de memória.

malloc(size) requisita pelo menos essa quantidade de bytes e retorna um ponteiro, ou NULL quando não consegue atender à requisição. Seus bytes não são inicializados para o programa. Para 10 inteiros, use malloc(10 * sizeof(int)); onde um inteiro tem 4 bytes, isso requisita 40 bytes. Para uma string, reserve espaço para seus caracteres mais um byte para o caractere nulo de término: malloc(strlen(s) + 1).

sizeof(a) mede o objeto chamado a. Se a for um ponteiro, ele fornece o tamanho do ponteiro, não o tamanho da alocação. Um ponteiro de 8 bytes pode se referir a um bloco de 40 bytes.

Saiba o que cada operação da biblioteca faz
ChamadaFinalidade principal
mallocObter um bloco cujos bytes não são zerados.
callocObter um bloco preenchido com bytes de valor zero.
reallocRedimensionar um bloco, possivelmente movendo-o.
freeDevolver um bloco alocado ao alocador.

free recebe o ponteiro retornado, sem um argumento de tamanho. O alocador mantém metadados de tamanho, geralmente em um cabeçalho antes do bloco. Passe o ponteiro retornado de um bloco atualmente alocado; um ponteiro para o interior do bloco não é um substituto válido. free(NULL) é válido e não faz nada. Essas funções são rotinas da biblioteca C, não chamadas de sistema.

Reconheça o erro pelo tempo de vida ou pelo limite

Um ponteiro sem uma alocação válida não pode ser usado como se já apontasse para uma área de armazenamento. Ler bytes recém-alocados antes de inicializá-los é uma leitura de memória não inicializada. Escrever além do fim da área alocada é um estouro de buffer; omitir o byte de término de uma string pode causar esse erro.

Após free, os ponteiros antigos para o bloco ficam pendentes. Acessar a memória por meio de um deles é um uso após liberação. Liberar o bloco novamente é uma dupla liberação. Liberar um endereço que o alocador não retornou para um bloco ativo é uma liberação inválida. Vazamento de um bloco é diferente: o bloco continua alocado, mas o programa deixa de liberá-lo quando deveria.

Entenda o que o hardware pode verificar

A compilação pode ser bem-sucedida apesar de todos esses erros. O hardware normalmente verifica regiões e permissões do processo, não cada alocação da biblioteca. Ultrapassar o limite de um bloco enquanto se permanece dentro da área de alocação dinâmica permitida do processo pode causar comportamento indefinido sem uma falha imediata. O programa pode corromper dados, falhar mais tarde, ler valores sem sentido ou parecer funcionar. Valgrind e AddressSanitizer podem detectar muitos desses erros durante a execução.

Principais conclusões

  • O tempo de vida de um bloco da área de alocação dinâmica é separado do tempo de vida da variável ponteiro.
  • Use sizeof para o tipo armazenado; sizeof aplicado a um ponteiro não mede seu bloco.
  • malloc, calloc, realloc e free são rotinas de biblioteca.
  • A alocação de uma string precisa de espaço para seu byte nulo de término.
  • free(NULL) não faz nada; um ponteiro para o interior de um bloco não é um ponteiro válido para o bloco alocado.
  • As verificações de região do hardware podem não detectar erros de memória nos limites de blocos dentro da área de alocação dinâmica.

2.2 Como o alocador obtém sua memória

A biblioteca C e o sistema operacional gerenciam a memória em escalas diferentes. O sistema operacional estabelece regiões no espaço de endereçamento de um processo e fornece a memória que as sustenta. O alocador divide a memória disponível da área de alocação dinâmica em blocos, registra os blocos livres e os reutiliza entre chamadas.

Mova o limite da área de alocação dinâmica

O limite da área de alocação dinâmica é o endereço imediatamente após o fim da área tradicional de alocação dinâmica. brk define esse limite em um endereço escolhido. sbrk(n) o move por um incremento em bytes e, em caso de sucesso, retorna o limite anterior. sbrk(0) informa o limite atual sem movê-lo.

Suponha que o limite seja 40.960 e que o alocador chame sbrk(8192) com sucesso. O valor retornado é 40.960. O novo limite é:

40.960+8.192=49.152

Os bytes adicionados ocupam os endereços virtuais de 40.960 a 49.151. O novo limite, 49.152, fica imediatamente após a região adicionada. Confundir o valor retornado com o novo limite desloca todos os cálculos posteriores de alocação.

As aplicações usam a biblioteca de alocação em vez de mover o limite diretamente. A biblioteca controla quais partes de sua região pertencem a ela. Alterações independentes nesse limite podem invalidar seus registros.

Obtenha um mapeamento separado

mmap pode criar uma região anônima: memória não vinculada a um arquivo, inicialmente preenchida com bytes de valor zero. munmap remove um mapeamento. Um alocador pode usar mapeamentos separados para alocações grandes e devolvê-los ao sistema operacional quando forem liberados.

Na glibc, o limiar inicial padrão para essa abordagem é 128 KB, ou 131.072 bytes, e pode ser aumentado. Uma alocação suficientemente grande geralmente é mapeada separadamente se não puder ser atendida pelo espaço livre existente. Essa é uma política da biblioteca, não uma linha divisória universal na linguagem C.

Libere no nível da biblioteca ou do sistema operacional
EventoO que muda
Liberar um pequeno bloco reutilizávelO alocador pode atender a outra requisição com ele.
Remover um mapeamento separadoA região mapeada deixa de pertencer ao processo.
Encerrar o processoO sistema operacional recupera a memória do processo.

Uma chamada a free geralmente devolve um bloco pequeno à reserva da biblioteca. Por isso, o processo pode apresentar o mesmo uso de memória posteriormente. A memória fica disponível para reutilização sem outra requisição ao sistema operacional.

O encerramento do processo recupera até as alocações que o programa deixou vazar. Durante a vida de um servidor de longa duração, porém, vazamentos repetidos continuam consumindo a memória disponível. A recuperação no encerramento não evita essa pressão enquanto ele executa.

Relacione o crescimento da área de alocação dinâmica à tradução

No modelo de segmentação, a área de alocação dinâmica é um segmento físico contíguo. Ampliá-la exige bytes físicos livres imediatamente acima dela. Se esses bytes estiverem ocupados, o sistema operacional pode mover o segmento para uma lacuna maior e atualizar seu estado de tradução. Se não houver uma região adequada disponível, a ampliação falhará. Se o alocador não conseguir obter espaço suficiente, malloc retornará NULL.

Principais conclusões

  • O sistema operacional fornece regiões; a biblioteca as divide em blocos.
  • Uma chamada bem-sucedida a sbrk retorna o limite anterior, não o novo.
  • mmap anônimo obtém uma região separada preenchida com zeros; munmap a remove.
  • Liberar um bloco geralmente permite sua reutilização sem reduzir a memória alocada ao processo pelo sistema operacional.
  • Uma área de alocação dinâmica segmentada precisa de espaço físico contíguo para crescer.
3

Tradução com base e limite

Base e limite transforma um endereço relativo ao processo em um endereço físico com uma comparação e uma soma. A simplicidade facilita a compreensão da divisão de trabalho: o hardware verifica cada acesso, enquanto o sistema operacional escolhe uma posição, restaura o estado de tradução ao trocar de processo e trata falhas. Acompanhar um processo nesses eventos também revela o principal custo: mesmo os endereços não usados entre a área de alocação dinâmica e a pilha ocupam parte de sua posição física.

3.1 Verificação e tradução de um endereço

A relocação dinâmica traduz endereços enquanto um programa executa. No modelo de base e limite, um processo ocupa uma região física contígua. Comece com espaços de endereçamento de mesmo tamanho que caibam na memória física; um par de registradores descreve então a região do processo em execução no momento.

Verifique primeiro o endereço virtual

O registrador base contém o endereço físico do primeiro byte da região. O registrador de limites, ou registrador limite, contém o tamanho da região em bytes. Para um endereço virtual não negativo, a regra é:

0≤enderec¸o virtual<limite

Se a verificação for bem-sucedida:

enderec¸o fıˊsico=base+enderec¸o virtual

Caso contrário, o hardware gera uma exceção. Um tamanho é uma contagem, portanto o endereço igual ao limite já está fora da região. Endereços virtuais negativos também são inválidos.

Examine os limites dos bytes

Considere um espaço de endereçamento de 8 KB com base 20.480 e limite 8.192. Seus bytes virtuais vão de 0 a 8.191. O endereço virtual 1.000 passa na verificação e alcança o byte físico 21.480. O último byte virtual permitido, 8.191, alcança 28.671. O endereço 9.000 falha porque é pelo menos 8.192; o hardware deve rejeitá-lo antes de realizar o acesso físico.

As buscas de instrução usam a mesma tradução que os dados. Se uma instrução no endereço virtual 128 lê do endereço virtual 3.000, a busca alcança o endereço físico 20.608 e a leitura alcança 23.480. São dois acessos à memória com dois endereços traduzidos, não uma única tradução compartilhada por toda a instrução.

Diferencie as convenções de limite
Conteúdo do registrador limiteO que é comparado
Tamanho da regiãoO endereço virtual deve ser menor que o tamanho.
Limite físico finalO endereço traduzido deve ser menor que esse limite.

A mesma região de 8 KB tem limite físico final 28.672. As duas convenções permitem exatamente os bytes de 20.480 a 28.671. Comparar o endereço físico 21.480 com o tamanho 8.192 mistura as duas convenções e rejeita incorretamente um acesso permitido.

Mova a memória sem alterar os ponteiros

A MMU, ou unidade de gerenciamento de memória, realiza as verificações e a soma. O sistema operacional pode pausar um processo, copiar sua região para outro lugar e alterar a base. O processo continua usando os mesmos endereços virtuais, por isso a relocação é dinâmica.

Na relocação estática, um carregador reescreve os endereços incorporados ao carregar o código. Reescrever uma referência de 1.000 para 21.480 registra uma localização física no programa. Movê-lo depois exige novas alterações, e a reescrita por si só não impede que um programa construa um endereço fora de sua região.

Some a base apenas a um endereço virtual. Somá-la a um endereço físico já traduzido desloca a localização uma segunda vez e destrói o mapeamento.

Principais conclusões

  • Quando o limite é um tamanho, verifique o endereço virtual antes de somar a base.
  • A faixa permitida exclui o endereço igual ao limite.
  • Buscas de instrução e acessos a dados são traduzidos.
  • Um limite físico final e um limite expresso em tamanho de bytes usam comparações diferentes.
  • A relocação dinâmica muda a localização sem reescrever ponteiros virtuais.

3.2 Instalação e troca do estado de tradução

O hardware mantém registradores de tradução para o processo em execução em uma CPU. O sistema operacional mantém o estado salvo dos processos em espera. A proteção depende de conceder apenas ao código privilegiado do sistema operacional o poder de alterar esse estado.

Forneça as operações de hardware

A CPU precisa dos modos usuário e núcleo, de um par de registradores base e limite em sua MMU e de circuitos para a verificação e a soma. Ela também precisa de operações privilegiadas para alterar o par e instalar tratadores de exceções. Endereços inválidos e tentativas de executar instruções privilegiadas em modo usuário devem gerar exceções.

Se um programa de usuário pudesse alterar sua base, poderia redirecionar seus endereços para o núcleo ou outro processo. As verificações de limite protegeriam então a região errada. Restringir alterações é, portanto, parte do mecanismo de proteção, não apenas uma conveniência administrativa.

Crie e execute um processo

Na inicialização, o sistema operacional instala seus tratadores de armadilhas e exceções, inicia o temporizador de interrupção e prepara seus registros de memória livre. Quando um processo começa, o sistema operacional encontra uma posição física para seu espaço de endereçamento. Com posições de mesmo tamanho, uma lista de blocos livres pode simplesmente registrar quais posições não estão em uso.

O sistema operacional marca a posição escolhida como ocupada, registra a base e o limite do processo, carrega os registradores e entra no modo usuário. O processo executa então diretamente na CPU. O hardware traduz os acessos comuns sem chamar o sistema operacional para cada byte.

Restaure o par correto em uma troca de contexto

Uma interrupção do temporizador transfere o controle ao sistema operacional. Ele salva os registradores do processo anterior, incluindo base e limite, em seu bloco de controle de processo e restaura os valores do próximo processo antes de retornar ao modo usuário.

Suponha que a base de A seja 20.480 e a de B seja 40.960, ambas com limite 8.192. O endereço virtual 1.000 de A alcança 21.480. Após a troca para B, o mesmo número virtual alcança 41.960. Restaurar os registradores da CPU sem restaurar o estado de tradução faria B acessar a região de A usando os ponteiros de B.

A CPU mantém o par ativo; cada processo tem seu próprio par salvo. Não imagine um único par permanente para toda a máquina nem suponha que o par de cada processo esteja ativo simultaneamente em uma CPU.

Mova, trate falhas e encerre

Para mover A para o endereço físico 49.152, o sistema operacional retira A da CPU, copia sua região de 8 KB e atualiza a base salva de A. Quando A retoma com essa base instalada, o endereço virtual 1.000 alcança 50.152. Seus valores de ponteiro virtual não precisam ser alterados.

Em um acesso inválido, o hardware gera uma exceção e transfere a execução para o modo núcleo no tratador registrado. O sistema operacional geralmente encerra o processo responsável. No encerramento, ele devolve a posição à lista de blocos livres e libera os registros do processo.

Principais conclusões

  • Somente código privilegiado pode alterar os registradores de tradução.
  • A CPU mantém o estado ativo; os blocos de controle de processo mantêm o estado salvo.
  • Uma troca de contexto deve restaurar base e limite junto com os outros registradores.
  • A relocação exige pausar o processo, copiar a região e atualizar a base salva.
  • O hardware gera exceções de acesso; o sistema operacional as trata.
  • O encerramento devolve a posição física à lista de blocos livres.

3.3 Por que uma posição simples desperdiça memória

Base e limite atende a dois objetivos com baixo custo: a tradução é transparente, e cada endereço é verificado em relação à região alocada. Seu principal ponto fraco é a relação entre essa região e os bytes que o processo realmente usa.

Reserve toda a extensão

O hardware precisa apenas de uma soma e uma comparação no caminho executado com frequência. Um alocador de posições de tamanho fixo também pode escolher rapidamente uma posição livre. Nenhuma dessas vantagens significa que a posição esteja cheia de dados úteis.

Na organização clássica, o código e a área de alocação dinâmica ficam perto de uma extremidade, e a pilha, perto da outra. Um único par de registradores base e limite traduz todo o intervalo. O espaço não usado entre a área de alocação dinâmica e a pilha ocupa memória física assim como as partes úteis.

Para um espaço de endereçamento de 16 KB que usa 1 KB de código, 2 KB de área de alocação dinâmica e 1 KB de pilha:

usado=1+2+1=4 KB na˜o usado=16−4=12 KB frac¸a˜o na˜o usada=1216=75%

O desperdício é fragmentação interna: bytes não usados dentro de uma região já alocada a um processo. Ele não resulta de uma escolha ruim de bloco pelo alocador da área de alocação dinâmica. Mesmo uma área de 2 KB perfeitamente ocupada deixa o grande espaço intermediário reservado.

Separe três questões de tamanho

A extensão do espaço de endereçamento, os bytes usados no momento e a memória física disponível são grandezas diferentes. Um espaço de 32 bits endereçado por byte abrange 232 bytes, ou 4 GB. Reservá-lo como um único bloco físico exige os 4 GB inteiros, mesmo que o processo use apenas alguns megabytes no momento.

RestriçãoConsequência
Uma região contíguaLacunas livres separadas não podem conter uma única região de processo.
Posições de mesmo tamanhoProcessos pequenos desperdiçam espaço; os maiores podem não caber.
Um espaço de endereçamento esparsoLacunas virtuais não usadas ainda consomem memória física reservada.

Tornar as posições de tamanho variável elimina a restrição de tamanho igual, mas não elimina a necessidade de uma lacuna contígua. Isso também cria um problema de alocação: o sistema operacional deve escolher entre lacunas livres de tamanhos diferentes. Reduzir uma posição não pode preservar tanto os endereços baixos do código quanto um endereço alto e distante da pilha se toda a extensão tiver de permanecer válida no mesmo mapeamento simples.

Realocar as regiões separadamente

Código, área de alocação dinâmica e pilha não precisam ser vizinhos na memória física para preservar a visão do programa. Dar a cada um sua própria base e seu próprio limite permite que o sistema operacional aloque apenas suas extensões usadas e deixe o espaço virtual sem memória física associada. Isso é segmentação, a generalização de um par de relocação para várias regiões lógicas.

Na organização de 16 KB acima, as três regiões usadas precisam de apenas 4 KB no total antes de sua própria sobrecarga de gerenciamento. A economia de espaço vem da mudança do que é realocado como uma unidade, não de tornar mais rápida a soma do registrador base.

Principais conclusões

  • Toda a extensão virtual ocupa uma posição física contígua.
  • O espaço não usado dentro dessa posição é fragmentação interna.
  • Posições de mesmo tamanho limitam processos grandes e desperdiçam espaço para os pequenos.
  • A segmentação economiza espaço ao realocar regiões usadas de forma independente.
4

Tradução com segmentos separados

Um único par de tradução reserva os espaços vazios dentro de um espaço de endereçamento. A segmentação dá ao código, à área de alocação dinâmica e à pilha localizações físicas independentes, de modo que apenas suas extensões atuais precisem de memória física associada. Traduzir um endereço passa a incluir a localização do segmento e de seu deslocamento, com uma mudança adicional de sinal para a pilha que cresce para baixo. A flexibilidade resultante permite proteção e compartilhamento de código, ao mesmo tempo que exige que o sistema operacional encontre lacunas contíguas para regiões de tamanhos diferentes.

4.1 Uma tradução própria para cada região

Um segmento é uma região contígua de um espaço de endereçamento com uma finalidade. No modelo clássico, código, área de alocação dinâmica e pilha recebem, cada um, um par de base e tamanho. Suas regiões físicas podem ser posicionadas independentemente, embora o processo mantenha sua organização virtual habitual.

Mapeie apenas as extensões usadas

Use um espaço de endereçamento de 16 KB com as seguintes posições. Os tamanhos usam KB binário, ou KiB.

SegmentoExtensão virtualBase física ou limite superiorTamanho
Código0 a 2.047Base 40.9602.048 bytes
Área de alocação dinâmica4.096 a 7.167Base 26.6243.072 bytes
Pilha14.336 a 16.383Limite superior 53.2482.048 bytes

O código e a área de alocação dinâmica crescem em direção aos endereços mais altos; a tradução da pilha usa seu limite superior e um deslocamento negativo. As três regiões físicas usam apenas 7 KB no total. As lacunas virtuais entre elas não precisam de armazenamento físico. Um segmento continua contíguo; o que deixa de exigir posições adjacentes é a relação entre segmentos.

Traduza um segmento que cresce para cima

Primeiro identifique o segmento. Depois calcule o deslocamento a partir de seu início virtual. Verifique se o deslocamento é não negativo e menor que o tamanho atual e, então, some-o à base física:

deslocamento=enderec¸o virtual−inıˊcio virtual do segmento enderec¸o fıˊsico=base do segmento+deslocamento

Para o endereço virtual 500, o deslocamento no código é 500. Ele é menor que 2.048, então o acesso alcança o endereço físico 41.460.

Para o endereço virtual 5.000, o deslocamento na área de alocação dinâmica é:

5.000−4.096=904

A verificação de tamanho é bem-sucedida porque 904 é menor que 3.072. O resultado é:

26.624+904=27.528

Somar o endereço virtual inteiro à base da área de alocação dinâmica produziria 31.624. Isso inclui incorretamente a posição inicial virtual da área em um cálculo que precisa apenas da distância dentro do segmento.

Verifique o segmento, não apenas a extensão do espaço de endereçamento

O endereço virtual 7.500 ainda cabe em 14 bits, mas isso não o torna permitido. Seu deslocamento na área de alocação dinâmica é 3.404, além da extensão atual de 3.072 bytes. O hardware gera uma exceção. Um endereço pode, portanto, estar dentro da extensão total do espaço de endereçamento e ainda assim fora de todas as regiões válidas.

O termo falha de segmentação surgiu para acessos inválidos em sistemas segmentados e continua em uso para acessos inválidos em sistemas com outros esquemas de tradução. O nome do erro, por si só, não identifica o mecanismo de tradução da máquina.

Principais conclusões

  • Cada segmento tem sua própria base e seu próprio tamanho.
  • O deslocamento de um segmento que cresce para cima é medido a partir do início virtual desse segmento.
  • Some à base física apenas o deslocamento verificado.
  • Um endereço dentro da extensão virtual total ainda pode causar uma falha.
  • Lacunas virtuais não usadas entre segmentos não precisam de memória física associada.

4.2 Seleção do segmento e extração de seu deslocamento

Antes que o hardware possa usar a base e o tamanho de um segmento, ele deve decidir a qual segmento um acesso se refere. Uma arquitetura explícita coloca essa escolha em bits do endereço. Uma arquitetura implícita a determina pela forma como a CPU gerou o endereço.

Divida um endereço de 14 bits

Reserve os dois bits mais altos para o número do segmento e os doze bits mais baixos para o deslocamento. O campo de dois bits tem quatro valores possíveis. Use 00 para código, 01 para área de alocação dinâmica e 11 para pilha; deixe 10 sem uso.

O campo de deslocamento pode representar 4.096 valores diferentes, de 0 a 4.095. Portanto, a janela virtual máxima de cada segmento é de 4 KB, mesmo quando a extensão válida atual do segmento é menor. Capacidade máxima e tamanho atual são limites diferentes.

Para o endereço virtual 5.000, a representação em 14 bits é:

01 0011 1000 1000

Os bits iniciais 01 selecionam a área de alocação dinâmica. Os bits restantes, 0011 1000 1000, correspondem a 904 em decimal. Com tamanho 3.072 e base física 26.624 para a área de alocação dinâmica, o deslocamento passa na verificação de tamanho e alcança o endereço físico 27.528.

Use uma máscara e um deslocamento de bits

A mesma divisão pode ser expressa em código:

segment = (va & 0x3000) >> 12;
offset = va & 0x0FFF;

A máscara 0x3000 mantém os dois bits de seleção; deslocá-los doze posições move-os para as posições mais baixas, fornecendo o número do segmento. A máscara 0x0FFF zera esses bits de seleção e mantém o deslocamento. Para va = 0x1388, os resultados são segmento 1 e deslocamento 0x388, ou 904.

Não some 0x1388 diretamente à base da área de alocação dinâmica. Esse valor inclui tanto o seletor de segmento quanto o deslocamento. O seletor escolhe os registradores; apenas o deslocamento participa da tradução dentro do segmento. O endereço físico resultante não precisa manter o padrão de bits do seletor.

Reconheça o custo da divisão

Um seletor de dois bits cria quatro janelas. Deixar 10 sem uso torna indisponível um quarto da extensão virtual de 16 KB. Nenhum segmento pode crescer além de sua janela de 4 KB apenas porque mais memória física ficou livre. Outras arquiteturas podem usar uma divisão diferente; combinar código e área de alocação dinâmica em um segmento permite que um único bit seletor o diferencie da pilha.

Deixe o tipo de acesso escolher

Em uma arquitetura implícita, as buscas de instrução usam o segmento de código porque seu endereço vem do contador de programa. Referências baseadas no ponteiro de pilha ou no ponteiro de quadro usam o segmento de pilha. Outros acessos usam o segmento da área de alocação dinâmica nesse modelo simplificado.

Método de seleçãoOrigem da escolha
ExplícitoUm campo de segmento dentro do endereço virtual
ImplícitoO registrador ou tipo de acesso que gerou o endereço

Principais conclusões

  • Os bits seletores escolhem o estado de tradução; os bits de deslocamento localizam um byte dentro da janela.
  • Doze bits de deslocamento permitem uma janela máxima de segmento de 4.096 bytes.
  • Máscaras e deslocamentos de bits separam os campos sem incluir os bits seletores na soma da base.
  • A seleção implícita usa a origem de um endereço, como o contador de programa ou o ponteiro de pilha.

4.3 Tradução da pilha e aplicação de permissões

A pilha cresce em direção aos endereços mais baixos. Sua tradução precisa de um bit de direção, além de uma base e um tamanho. Neste modelo, 1 indica crescimento para cima e 0 indica crescimento para baixo. As permissões de acesso acrescentam outra verificação independente: um byte pode estar dentro dos limites e ainda assim não permitir a operação solicitada.

Trate a base da pilha como um limite superior

Para um segmento que cresce para cima, a base identifica seu primeiro byte físico. Para um segmento que cresce para baixo, a base identifica o limite imediatamente acima de seu byte físico mais alto. Na organização usada no exemplo, a base 53.248 e o tamanho 2.048 da pilha abrangem os bytes físicos de 51.200 a 53.247.

Para a janela de pilha de 4 KB selecionada por 11, converta o campo de deslocamento de doze bits em um deslocamento negativo:

deslocamento negativo=campo de deslocamento−4.096

O campo varia de 0 a 4.095, portanto esse deslocamento é sempre negativo. Ele é válido quando seu módulo não excede o tamanho atual da pilha. Em seguida, some o deslocamento com sinal à base.

Examine um acesso permitido à pilha

O endereço virtual 15.500 seleciona a pilha. Sua janela começa no endereço virtual 12.288, portanto seu campo de deslocamento é 3.212. Converta o campo:

3.212−4.096=−884

A profundidade 884 está dentro do tamanho 2.048. A tradução resulta em:

53.248−884=52.364

Somar o valor positivo 3.212 à base apontaria para cima da pilha. O campo ainda não é o deslocamento necessário para um segmento que cresce para baixo.

O endereço virtual 13.000, por sua vez, fornece o campo 712 e o deslocamento −3.384. Sua profundidade excede 2.048, então o hardware gera uma falha. Se o sistema operacional ampliar a pilha com sucesso, o aumento de seu tamanho poderá tornar válidos mais endereços baixos.

Inclua o extremo inferior

Um deslocamento de −2.048 alcança o byte mais baixo da pilha, 51.200, e é permitido. Um deslocamento de −2.049 está fora dela. Portanto, a verificação para crescimento descendente inclui o módulo igual ao tamanho. Isso corresponde à contagem de bytes da regra para crescimento ascendente, embora essa regra exclua um deslocamento igual ao tamanho: a base ascendente é um byte, enquanto a base descendente é um limite final.

Verifique a operação solicitada

Os bits de proteção registram as permissões de leitura, escrita e execução. O código normalmente permite leitura e execução; a área de alocação dinâmica e a pilha normalmente permitem leitura e escrita. Uma escrita em código com permissão de leitura e execução causa uma falha mesmo quando seu deslocamento é válido. Executar dados também causa uma falha quando não há permissão de execução.

Código somente de leitura pode ser compartilhado. O sistema operacional pode apontar os segmentos de código de dois processos para a mesma região física e negar escritas em ambos. Os bytes de instrução ocupam uma única cópia física, enquanto cada processo mantém uma área de alocação dinâmica e uma pilha separadas.

Principais conclusões

  • A base de um segmento que cresce para baixo marca seu limite superior, não um byte armazenado.
  • Subtraia o tamanho máximo da janela do campo de deslocamento para obter o deslocamento negativo.
  • O byte mais baixo da pilha é permitido quando o módulo do deslocamento é igual ao tamanho atual.
  • Tanto os limites quanto a operação solicitada devem passar pelas verificações do hardware.
  • O compartilhamento de código somente de leitura economiza memória física enquanto as regiões privadas graváveis permanecem separadas.

4.4 Gerenciamento de segmentos físicos de tamanhos variados

A segmentação substitui uma região grande por várias menores. Isso evita associar memória física a lacunas virtuais vazias, mas agora o sistema operacional deve posicionar e ampliar regiões de tamanhos diferentes enquanto preserva o estado de tradução de cada processo.

Salve todas as partes do mapeamento

Em uma troca de contexto, apenas a base e o tamanho já não são suficientes. O sistema operacional salva e restaura a base, o tamanho, a direção de crescimento e as permissões de cada segmento. Restaurar uma pilha com a direção errada ou código com as permissões erradas mudaria o significado de endereços que, de outro modo, seriam idênticos.

Quando um alocador precisa de mais espaço na área de alocação dinâmica, o sistema operacional deve ampliar seu segmento físico. Bytes livres imediatamente acima dele permitem o crescimento direto. Caso contrário, o sistema operacional pode movê-lo para uma lacuna maior adequada e atualizar sua base. Se não conseguir obter uma região adequada, a ampliação falhará.

Escolha a granularidade
EsquemaOrganizaçãoConsequência para o gerenciamento
Segmentação de granularidade grossaAlgumas regiões, como código, área de alocação dinâmica e pilhaUm pequeno conjunto de registradores de segmento descreve o processo.
Segmentação de granularidade finaMuitas regiões, talvez uma por estrutura de dadosUma tabela de segmentos na memória permite mais opções de compartilhamento e proteção.

O Multics usava segmentação de granularidade fina. Mais segmentos permitem unidades menores de controle, mas exigem mais metadados de tradução e gerenciamento.

Encontre uma lacuna suficientemente grande

Segmentos físicos de tamanhos variáveis deixam lacunas livres de tamanhos variáveis à medida que processos começam, crescem e terminam. A fragmentação externa ocorre quando há bytes livres suficientes no total, mas nenhuma lacuna individual pode conter o segmento solicitado.

Suponha que as lacunas livres tenham 8 KB, 6 KB e 10 KB. Seu total é 24 KB. Um segmento de área de alocação dinâmica de 12 KB ainda não cabe: a maior lacuna disponível tem apenas 10 KB. Juntar as lacunas no papel não torna seus endereços físicos adjacentes.

A compactação pode corrigir essa organização. O sistema operacional pausa os processos, copia os segmentos para ficarem lado a lado e atualiza suas bases. Os endereços virtuais continuam funcionando porque a tradução oculta as movimentações físicas. O resultado é uma grande região livre contígua, mas a cópia é custosa e novas alocações podem fragmentar a memória novamente.

Políticas de alocação como primeiro ajuste e melhor ajuste procuram limitar sobras inadequadas sem copiar. Nenhuma política de alocação de tamanhos variáveis elimina a fragmentação externa para toda sequência de requisições. Um único segmento grande também pode desperdiçar espaço dentro de sua própria extensão quando apenas partes dispersas são usadas.

Reconheça o modelo nos sistemas modernos

A paginação divide a memória em partes de tamanho fixo e evita exigir que cada região lógica ocupe uma única lacuna física. O modelo de segmentação continua útil para entender regiões, proteção e compartilhamento. No modo de 64 bits do x86-64, as bases comuns dos segmentos de código, dados e pilha funcionam como zero e seus limites não são verificados; FS e GS mantêm bases úteis para dados específicos de cada thread ou CPU. Uma mensagem de acesso inválido chamada falha de segmentação não significa que o modelo clássico de três segmentos esteja ativo.

Principais conclusões

  • Trocas de contexto restauram direção e permissões, além de bases e tamanhos.
  • A segmentação de granularidade fina fornece mais regiões independentes por meio de uma tabela de segmentos.
  • A fragmentação externa depende dos tamanhos das lacunas individuais, não apenas de seu total.
  • A compactação move segmentos físicos e atualiza bases, preservando os ponteiros virtuais.
  • Políticas de alocação reduzem a fragmentação sem garantir sua eliminação.
  • A tradução comum no x86-64 difere da segmentação clássica.
5

Gerenciamento de blocos livres e seus custos

Um alocador deve saber quais bytes estão livres e escolher um bloco que possa conter cada requisição. A divisão e a coalescência alteram a lista de blocos livres; as políticas de alocação mudam quais lacunas permanecem para requisições posteriores. Cabeçalhos, alinhamento e arredondamento para potências de dois acrescentam seus próprios custos. Acompanhar essas mudanças permite explicar falhas de alocação, comparar políticas e entender por que caches especializados e a alocação de blocos parceiros trocam flexibilidade por velocidade.

5.1 Localização do desperdício dentro ou entre blocos

O gerenciamento de espaço livre registra a memória disponível e escolhe onde cada requisição será colocada. Requisições de mesmo tamanho podem usar uma lista de blocos intercambiáveis. Tamanhos variáveis são mais difíceis: tanto um alocador da área de alocação dinâmica quanto um sistema operacional que posiciona segmentos devem encontrar um bloco contíguo grande o suficiente para a próxima requisição.

Localize a fragmentação externa

Considere uma região de 60 bytes com os bytes de 0 a 19 livres, um bloco alocado de 20 a 39 e os bytes de 40 a 59 livres. Há quarenta bytes livres, mas nenhuma das lacunas livres pode conter uma requisição de 25 bytes. O bloco ativo do meio impede que essas lacunas sejam tratadas como uma única região.

Isso é fragmentação externa: há capacidade livre fora dos blocos alocados, mas sua disposição a torna inutilizável para uma determinada requisição contígua. Os bytes livres não desapareceram. Eles ainda podem atender a requisições menores ou se tornar úteis quando os blocos intermediários forem liberados.

Localize a fragmentação interna

Um alocador que arredonda requisições para múltiplos de 16 fornece um bloco de 32 bytes para uma requisição de 20 bytes. Os 12 bytes adicionais ficam dentro de uma alocação já fornecida. Esse desperdício é fragmentação interna.

O espaço não usado entre a área de alocação dinâmica e a pilha em uma posição de base e limite é outro exemplo. A alocação de blocos parceiros introduz o mesmo tipo de desperdício quando arredonda para potências de dois. O nível de gerenciamento é diferente, mas a localização do espaço não usado é a característica decisiva.

DesperdícioOnde ficaPor que tem custo
Fragmentação internaDentro de uma região alocadaOs bytes reservados excedem o conteúdo útil.
Fragmentação externaEm lacunas livres separadasNenhuma lacuna individual comporta a extensão solicitada.

Um alocador pode sofrer os dois tipos. Arredondar uma requisição pode desperdiçar bytes dentro de seu bloco enquanto outros blocos livres permanecem separados em outro lugar.

Una blocos livres vizinhos sem mover dados ativos

A coalescência une blocos livres fisicamente adjacentes. Se o bloco do meio na região de 60 bytes for liberado, as três partes poderão formar uma única lacuna de 60 bytes. Se o bloco do meio continuar alocado, a coalescência não poderá atravessá-lo. A união reduz a fragmentação externa, mas não garante uma lacuna suficientemente grande para toda requisição.

Adicionar mais memória a uma área de alocação dinâmica pode aliviar a pressão, mas não muda os endereços dos blocos ativos existentes. Sua disposição ainda pode deixar pequenas lacunas inutilizáveis.

Explique por que o sistema operacional pode compactar segmentos

O sistema operacional pode copiar segmentos físicos e atualizar suas bases. Os programas mantêm endereços virtuais, portanto o mapeamento pode ocultar essas movimentações. Um alocador geral de C para a área de alocação dinâmica não tem uma camada de tradução entre os ponteiros retornados e as localizações dentro da área. Um programa pode ter copiado um ponteiro para muitos objetos, e o alocador não consegue descobrir e reescrever cada cópia.

Mover um bloco ativo da área de alocação dinâmica por conta própria deixaria esses ponteiros apontando para sua localização antiga. Consequentemente, o gerenciamento comum com malloc mantém blocos ativos nos endereços retornados até que sejam liberados. Ele deve controlar a fragmentação por meio de alocação, reutilização, divisão e união do espaço livre.

Principais conclusões

  • O desperdício interno fica dentro das alocações; a fragmentação externa fica em lacunas livres separadas.
  • A capacidade livre total não garante que uma requisição contígua caiba.
  • A coalescência une blocos livres adjacentes sem mover blocos ativos.
  • A relocação de segmentos pelo sistema operacional pode preservar ponteiros por meio da tradução; a compactação comum da área de alocação dinâmica em C não pode.

5.2 Acompanhamento de cabeçalhos, divisões e uniões

Uma lista de blocos livres registra blocos livres por endereço e tamanho. A alocação divide um bloco ou o remove da lista; a liberação devolve um bloco e pode uni-lo aos vizinhos. A convenção de tamanho importa: um tamanho registrado pode significar a área útil utilizável ou o bloco inteiro, incluindo metadados.

Divida e una intervalos simples

Primeiro ignore os cabeçalhos. Em uma região de 60 bytes com entradas livres (0, 20) e (40, 20), uma requisição de 8 bytes colocada no início retorna o endereço 0. As entradas restantes são (8, 12) e (40, 20).

Partindo novamente da organização original, libere os bytes alocados do meio, de 20 a 39. Sem união, três entradas de 20 bytes ainda não podem atender individualmente a uma requisição de 30 bytes. A coalescência de intervalos adjacentes produz (0, 60), que pode atendê-la. A ordem de endereço ajuda o alocador a reconhecer vizinhos; a proximidade na lista, por si só, não basta se seus intervalos físicos não forem contíguos.

Recupere o cabeçalho a partir do ponteiro do usuário

free(ptr) não recebe um tamanho. Um alocador simples armazena um cabeçalho de tamanho imediatamente antes da área útil, às vezes com um valor de verificação ou número mágico. Subtrair o comprimento do cabeçalho permite encontrar os metadados.

Com um cabeçalho de 16 bytes, uma requisição de 96 bytes ocupa 112 bytes no total. O programa recebe um ponteiro 16 bytes após o início do bloco. Liberá-lo devolve toda a extensão de 112 bytes, incluindo o cabeçalho, para gerenciamento futuro. O alinhamento pode acrescentar arredondamento; os tamanhos deste exemplo já atendem ao alinhamento de 16 bytes.

Acompanhe uma lista de blocos livres embutida

Suponha que uma área de alocação dinâmica de 4.096 bytes comece em 32.768. Um nó livre usa 16 bytes e registra os bytes utilizáveis após o nó. Inicialmente, ele registra 4.080 bytes utilizáveis.

Três requisições de 96 bytes consomem 112 bytes cada:

RequisiçãoEndereço do cabeçalhoPonteiro retornado
Primeira32.76832.784
Segunda32.88032.896
Terceira32.99233.008

O nó livre restante começa em 33.104. Seu tamanho utilizável é de 3.744 bytes. A contabilização é:

336+16+3.744=4.096

Liberar o ponteiro 32.896 leva ao cabeçalho 32.880. Esse bloco se torna um nó livre com 96 bytes utilizáveis. Ele não pode se unir ao nó final em 33.104 porque a terceira alocação está entre eles. Quando as três alocações são liberadas e unidas por coalescência, um único nó volta a descrever 4.080 bytes utilizáveis. A incorporação dos antigos cabeçalhos internos torna seus bytes disponíveis dentro da extensão resultante da união.

Mantenha os registros dentro da região gerenciada

Nós de lista embutidos ficam na própria memória livre, portanto gerenciar a lista não exige uma alocação separada para cada entrada. O nó contém um tamanho e uma ligação para o próximo bloco livre. Se nenhum bloco couber, o alocador pode requisitar mais memória com sbrk ou mmap; se não conseguir obter memória suficiente, o resultado será NULL.

Um estouro pode sobrescrever um cabeçalho ou nó vizinho. Isso explica por que a falha visível pode ocorrer durante uma chamada posterior a malloc ou free, depois da escrita que danificou a lista.

Principais conclusões

  • Diferencie o tamanho utilizável da extensão total, incluindo metadados.
  • Um cabeçalho de 16 bytes faz uma requisição de 96 bytes consumir 112 bytes.
  • Encontre um cabeçalho de alocação subtraindo seu tamanho do ponteiro retornado.
  • A divisão preserva uma sobra utilizável; a coalescência exige extensões livres adjacentes.
  • Nós embutidos armazenam os metadados da lista nos próprios blocos livres.
  • Um bloco ativo intermediário impede a união.
  • Sobrescrever registros pode causar falhas em chamadas posteriores ao alocador.

5.3 Escolha de um bloco livre

Uma política de alocação escolhe entre blocos suficientemente grandes para uma requisição. Escolhas diferentes deixam lacunas diferentes para requisições futuras. O tempo de busca importa junto com a fragmentação, e nenhuma política vence para toda carga de trabalho.

Compare as regras de busca
PolíticaEscolhaPrincipal compromisso
Melhor ajusteMenor bloco em que a requisição cabeUma busca completa em uma lista simples pode deixar sobras minúsculas.
Pior ajusteMaior blocoUma busca completa em uma lista simples pode consumir uma lacuna grande valiosa.
Primeiro ajustePrimeiro bloco adequado na ordem da listaPara cedo, mas pequenas sobras se acumulam perto do início.
Próximo ajustePrimeiro bloco adequado a partir de uma posição de busca salvaDistribui as buscas pela lista, voltando ao início quando necessário.

Para melhor e pior ajuste, uma lista simples não ordenada exige uma busca completa. Outras estruturas podem encontrar tamanhos adequados mais rapidamente. Primeiro ajuste significa o primeiro na ordem escolhida para a lista, o que não precisa ser o menor endereço, a menos que a lista esteja ordenada por endereço.

Acompanhe a primeira requisição

Considere blocos livres de 30, 12, 50 e 20 bytes em ordem de endereço. Ignore os cabeçalhos e suponha que a divisão possa preservar cada sobra. Uma requisição de 18 bytes altera a lista da seguinte forma:

  • O melhor ajuste usa 20 e deixa 30, 12, 50, 2.
  • O pior ajuste usa 50 e deixa 30, 12, 32, 20.
  • O primeiro ajuste usa 30 e deixa 12, 12, 50, 20.
  • O próximo ajuste, começando no quarto bloco, usa 20 e deixa 30, 12, 50, 2.

O próximo ajuste precisa de uma posição inicial para determinar sua escolha. O nome, por si só, não implica a primeira entrada da lista. Um acompanhamento deve manter esse estado de busca entre requisições.

Veja por que a próxima requisição muda a avaliação

Uma requisição seguinte pede 45 bytes. O melhor ajuste e o primeiro ajuste preservaram o bloco de 50 bytes, então ambos atendem à requisição. O maior bloco restante do pior ajuste tem 32 bytes, então ele falha apesar dos 94 bytes livres no total:

30+12+32+20=94

Essa falha é fragmentação externa. A decisão anterior dividiu a única lacuna suficientemente grande. Por outro lado, o melhor ajuste deixou uma pequena sobra de 2 bytes que pode ser pequena demais para requisições futuras úteis. Uma sobra imediata pequena não prova que uma política usará bem o espaço ao longo de toda a sequência de requisições.

Equilibre política e estrutura de dados

Percorrer milhares de entradas pode ser custoso mesmo quando cada escolha de alocação é boa. Alocadores práticos agrupam blocos por tamanho ou usam estruturas de busca, como árvores balanceadas. Uma lista ordenada por endereço também favorece a coalescência ao facilitar a localização de vizinhos físicos.

O mecanismo de alocação: encontrar, dividir e atualizar metadados, pode permanecer o mesmo enquanto a política muda. Para comparar políticas de forma justa, acompanhe as mesmas requisições e liberações, mantenha fixas as regras de sobrecarga e considere tanto as lacunas resultantes quanto a quantidade de busca.

Principais conclusões

  • O melhor ajuste escolhe o menor bloco suficiente; o pior ajuste escolhe o maior.
  • O primeiro ajuste depende da ordem da lista; o próximo ajuste também depende da posição de busca salva.
  • Uma escolha que atende a uma requisição pode impedir uma requisição maior posterior.
  • Nenhuma política de alocação é a melhor para toda carga de trabalho.
  • As estruturas de dados afetam o custo da busca independentemente da regra de seleção.

5.4 Reutilização de tamanhos, objetos e blocos parceiros

A busca geral em listas de blocos livres é flexível, mas pode ser custosa. Alocadores especializados tornam as requisições comuns previsíveis ao agrupar tamanhos, manter objetos reutilizáveis ou restringir tamanhos de blocos a potências de dois.

Reutilize tamanhos frequentes e objetos inicializados

Listas segregadas mantêm listas de blocos livres separadas para tamanhos frequentes, com um alocador geral para outras requisições. Uma requisição de tamanho comum pode ser atendida diretamente por um bloco de sua lista. Blocos de mesmo tamanho não criam fragmentação externa entre si, mas a divisão da capacidade entre listas é uma escolha de política: blocos disponíveis de um tamanho podem não atender a outro tamanho.

Um alocador slab mantém um cache de objetos para um tipo de objeto do núcleo usado repetidamente, como um nó-i, uma trava ou um descritor de processo. Um slab é dividido em objetos desse tipo. O cache obtém mais slabs quando necessário e pode devolver um slab totalmente livre a um alocador geral. Jeff Bonwick projetou essa abordagem para o Solaris.

O cache mantém os objetos liberados em estado inicializado, evitando preparação e destruição repetidas. Isso economiza tempo além do gasto na própria busca.

Divida uma região de blocos parceiros

Um alocador binário de blocos parceiros começa com uma região cujo tamanho é uma potência de dois e arredonda cada requisição para um tamanho de bloco que seja potência de dois. Ele divide repetidamente um bloco livre em metades iguais até que uma metade tenha o tamanho mínimo adequado. As duas metades de uma divisão são blocos parceiros.

Para uma requisição de 5 KB em uma região de 64 KB, arredonde 5 KB para 8 KB. Divida 64 em dois blocos de 32 KB, depois os 32 escolhidos em dois blocos de 16 KB e, então, os 16 escolhidos em dois blocos de 8 KB. Retornar o primeiro bloco de 8 KB deixa blocos parceiros livres nos deslocamentos 8 KB, 16 KB e 32 KB, com tamanhos de 8 KB, 16 KB e 32 KB, respectivamente.

A alocação desperdiça 3 KB dentro de seu bloco de 8 KB. Isso é fragmentação interna, aceita em troca de divisão e união regulares.

Encontre o único parceiro permitido para união

Usando deslocamentos medidos a partir do início da região gerenciada:

deslocamento do bloco parceiro=deslocamento do bloco⊕tamanho do bloco

O ou exclusivo inverte o bit correspondente ao tamanho do bloco. Para um bloco de 8 KB no deslocamento 0, seu parceiro está no deslocamento 8.192. Para um bloco de 16 KB no deslocamento 16.384, seu parceiro está em 0.

Quando o primeiro bloco de 8 KB é liberado, ele se une a seu parceiro livre de 8 KB. O bloco de 16 KB resultante pode se unir a seu parceiro livre e, depois, o bloco de 32 KB resultante pode se unir novamente. A união para se o parceiro necessário de mesmo tamanho estiver em uso. Estar adjacentes e livres não é suficiente quando dois blocos não são parceiros da mesma divisão.

Uma requisição de 20 KB recebe 32 KB, desperdiçando 12 KB, ou 37,5% do bloco. O Linux combina a alocação de blocos parceiros para memória física com caches de objetos do tipo slab. Alocadores para múltiplas threads também usam caches locais ou múltiplas arenas para reduzir a espera por uma única trava de alocação compartilhada; glibc, jemalloc e tcmalloc usam versões dessas ideias.

Principais conclusões

  • Listas segregadas aceleram requisições de tamanhos comuns.
  • Caches slab reutilizam tipos de objetos recorrentes e podem evitar inicializações repetidas.
  • A alocação de blocos parceiros arredonda para potências de dois e divide em metades iguais.
  • A identificação do bloco parceiro usa o deslocamento relativo à região XOR o tamanho do bloco.
  • Somente um bloco parceiro livre de mesmo tamanho pode ser unido em cada nível.
  • O arredondamento para potências de dois troca fragmentação interna por gerenciamento simples.

Exercícios resolvidos de Tradução de endereços

5 Lições Interativas

1

Acompanhe um ponteiro em uma visão privada da memória

8 passos
Relacione a organização do processo à tradução, ao isolamento e à execução eficiente.
  1. 1
    IntroduçãoUma máquina, várias visões da memória

    Vários processos podem permanecer na memória física enquanto a CPU alterna entre eles. Cada um precisa de uma visão estável de suas próprias instruções e dados, mesmo quando outros processos começam, param ou são movidos.

    Um espaço de endereçamento fornece essa visão. O ponteiro usado por um processo pertence a essa visão; o sistema operacional e o hardware determinam o byte físico alcançado pelo acesso.

  2. 2
    ExplicaçãoPosicione o conteúdo do programa

    O código armazena instruções, os dados estáticos armazenam variáveis globais e locais estáticas, a área de alocação dinâmica armazena blocos requisitados e a pilha armazena o estado das chamadas de função.

    Na organização clássica, a área de alocação dinâmica cresce para cima e a pilha para baixo, avançando sobre um espaço entre elas. Com tamanhos binários, 1 KB significa 1.024 bytes, também chamado de 1 KiB. Um espaço de 16 KB tem bytes de 0 a 16.383; seu limite superior não é, ele próprio, um byte no espaço.

  3. 3
    ExemploDê dois significados ao mesmo número

    O processo A e o processo B usam o endereço virtual 1.000. A tradução de A pode enviá-lo a um byte físico, enquanto a de B o envia a outro. O número do ponteiro, por si só, não identifica armazenamento compartilhado.

    Da mesma forma, imprimir &x mostra um endereço virtual. Mover o armazenamento físico subjacente não precisa alterar o valor do ponteiro que o programa vê.

  4. 4
    DesafioInterprete dois ponteiros impressos

    Dois processos imprimem o mesmo valor de ponteiro. Eles necessariamente estão lendo o mesmo byte físico? Explique o que determina o destino.

    ---reveal---

    Não. Cada ponteiro impresso é interpretado no espaço de endereçamento do próprio processo. O mapeamento ativo determina o destino físico, portanto números virtuais iguais podem alcançar bytes diferentes. Para alcançar o mesmo byte físico, seriam necessários mapeamentos que realmente compartilhassem armazenamento.

  5. 5
    ExplicaçãoTraduza rapidamente e imponha limites

    A transparência preserva a visão privada do programa. A eficiência de tempo mantém baixo o custo da tradução em cada busca, leitura e escrita. A eficiência de espaço limita metadados e capacidade desperdiçada. A proteção impede acessos não autorizados.

    O hardware cuida da tradução rotineira. O sistema operacional configura os mapeamentos, escolhe as posições e assume o controle quando um acesso gera uma exceção.

  6. 6
    DesafioSepare a escolha da operação

    Um gerenciador de memória deixa de escolher a primeira lacuna adequada e passa a escolher a menor lacuna adequada. O hardware continua verificando limites e somando uma base. O mecanismo ou a política mudou?

    ---reveal---

    A política de alocação mudou: ela agora faz uma escolha diferente entre as lacunas. O mecanismo de tradução permanece igual. O mesmo hardware pode traduzir e proteger uma região independentemente de qual lacuna adequada o sistema operacional escolheu.

  7. 7
    DesafioRelacione movimentação e proteção

    Um sistema operacional move um processo pausado para uma nova região física, mas preserva seus valores de ponteiro. Por que isso exige tanto tradução quanto controle sobre quem pode alterar o mapeamento?

    ---reveal---

    A tradução redireciona os ponteiros virtuais inalterados para os bytes copiados. Somente código privilegiado do sistema operacional pode instalar o novo mapeamento; caso contrário, um processo poderia redirecionar a si mesmo para outro processo ou para o núcleo. Ponteiros estáveis fornecem transparência, enquanto mapeamentos controlados preservam o isolamento.

  8. 8
    RecapitulaçãoInterprete o ponteiro em seu processo

    Um espaço de endereçamento organiza o código e os dados de um processo independentemente da localização física. Um ponteiro virtual ganha significado por meio do mapeamento do processo em execução.

    Avalie uma arquitetura pela visão que preserva, pelo tempo e espaço que custa e pelos limites de acesso que impõe. Políticas escolhem posições; mecanismos realizam a tradução e as verificações.

2

Acompanhe uma requisição à área de alocação dinâmica entre a biblioteca e o sistema operacional

12 passos
Acompanhe os tempos de vida dos blocos, as chamadas de biblioteca, o crescimento do limite da área de alocação dinâmica e os mapeamentos separados.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoConsidere os dois níveis de posse
  2. 2
    ExemploSepare um ponteiro de sua alocação
  3. 3
    ExplicaçãoRequisite bytes suficientes
  4. 4
    DesafioPreveja o que permanece após um retorno
  5. 5
    ExplicaçãoLibere apenas um bloco ativo
  6. 6
    Ideia-chaveUma região permitida pode conter um acesso inválido a um objeto
  7. 7
    ExplicaçãoAmplie uma região e depois a divida
  8. 8
    DesafioLocalize os bytes recém-adicionados
  9. 9
    ConexãoLibere um bloco ou remova um mapeamento
  10. 10
    DesafioExplique um uso de memória estável
  11. 11
    DesafioAcompanhe o crescimento com segmentação
  12. 12
    RecapitulaçãoAcompanhe separadamente o tempo de vida e a posse
3

Execute e mova um processo com base e limite

13 passos
Traduza acessos, restaure o mapeamento correto e calcule o desperdício de espaço reservado.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoDescreva uma posição física
  2. 2
    ExplicaçãoAplique a convenção de tamanho
  3. 3
    ExemploTraduza a busca e a leitura
  4. 4
    DesafioVerifique o último byte
  5. 5
    DicaReconheça a alternativa para o registrador limite
  6. 6
    ExplicaçãoProteja os registradores de tradução
  7. 7
    ExemploTroque a visão da memória junto com o estado da CPU
  8. 8
    DesafioEncontre uma restauração ausente
  9. 9
    ConexãoMova um processo sem reescrever ponteiros
  10. 10
    ExemploMeça a extensão não usada
  11. 11
    DesafioEscolha a unidade de relocação
  12. 12
    DesafioMantenha o limite após uma movimentação
  13. 13
    RecapitulaçãoDiferencie as coordenadas e os custos
4

Traduza código, área de alocação dinâmica e uma pilha que cresce para baixo

17 passos
Extraia campos de segmento, verifique os extremos exatos e relacione o compartilhamento à localização física.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoDivida o processo em regiões lógicas
  2. 2
    ExplicaçãoConfigure a organização do exemplo
  3. 3
    ExemploEncontre o deslocamento na área de alocação dinâmica
  4. 4
    DesafioTeste um byte além da área de alocação dinâmica
  5. 5
    ExplicaçãoUse bits seletores para escolher registradores
  6. 6
    ExemploExtraia os dois campos
  7. 7
    DesafioSepare a capacidade do uso atual
  8. 8
    ConexãoDeixe o acesso escolher um segmento
  9. 9
    ExplicaçãoMeça para baixo a partir de um limite superior
  10. 10
    ExemploCalcule um deslocamento com sinal na pilha
  11. 11
    DesafioInclua o byte mais baixo da pilha
  12. 12
    Ideia-chaveVerifique a permissão após encontrar uma localização válida
  13. 13
    ExplicaçãoRestaure mais que uma base
  14. 14
    DesafioConte as lacunas separadamente
  15. 15
    ConexãoEntenda os limites da compactação
  16. 16
    DesafioMova um segmento compartilhado com segurança
  17. 17
    RecapitulaçãoEncontre a região antes do byte físico
5

Acompanhe blocos livres e escolha políticas de alocação

18 passos
Acompanhe metadados, compare sequências de alocação e divida e una blocos parceiros.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoPergunte se a requisição cabe em um bloco
  2. 2
    ExemploLocalize a capacidade não usada
  3. 3
    DesafioTeste o que a união pode realizar
  4. 4
    ConexãoExplique por que ponteiros ativos impedem a compactação da área de alocação dinâmica
  5. 5
    ExplicaçãoContabilize o cabeçalho
  6. 6
    ExemploPosicione três blocos
  7. 7
    ExemploVerifique a extensão restante
  8. 8
    DesafioRecupere um cabeçalho e uma extensão
  9. 9
    ExplicaçãoDeixe a política escolher o bloco
  10. 10
    ExemploCompare a primeira escolha
  11. 11
    DesafioAntecipe a próxima requisição
  12. 12
    ConexãoTorne previsíveis as requisições comuns
  13. 13
    ExemploArredonde e divida uma região de blocos parceiros
  14. 14
    ExplicaçãoEncontre o bloco parceiro correspondente
  15. 15
    DesafioAcompanhe os níveis de união
  16. 16
    Ideia-chavePague pela simplicidade dentro do bloco
  17. 17
    DesafioSepare a escolha da posição da união
  18. 18
    RecapitulaçãoAcompanhe a organização e a contabilização

Questões de Tradução de endereços

50 Questões de Prática em 5 conjuntos

Conjunto 1: Espaços de endereçamento, verificações e primeiras alocações10 Questões de Prática

Questão 1 de 10

Dois processos imprimem, cada um, um ponteiro cujo valor numérico é 2.400. O que isso informa sobre seu armazenamento físico?
  1. Seus bytes devem ocupar o mesmo endereço físico na memória.
  2. Seus mapeamentos podem colocar os bytes em endereços físicos diferentes.
  3. Seus bytes devem ter conteúdos idênticos nesse endereço virtual.
  4. Seus endereços virtuais devem mudar antes que qualquer processo execute.
Mostrar respostaOcultar resposta
Resposta: B
Cada ponteiro é interpretado no espaço de endereçamento do próprio processo, portanto valores virtuais iguais podem alcançar bytes físicos diferentes. Números iguais não comprovam armazenamento compartilhado. Para isso, os mapeamentos teriam de identificar a mesma região subjacente.

Questão 2 de 10

Um sistema operacional altera a forma como seleciona uma posição livre para um processo, mantendo o mesmo hardware de verificação de limites. O que mudou?
  1. A regra de privilégio do modo usuário mudou.
  2. A política de alocação mudou.
  3. A largura do endereço do processo mudou.
  4. O mecanismo de relocação mudou.
Mostrar respostaOcultar resposta
Resposta: B
A política escolhe uma posição entre as alternativas disponíveis. O mecanismo continua verificando os limites e somando a base selecionada exatamente como antes. Chamar isso de um novo mecanismo de relocação confunde a decisão de alocação com as operações que a implementam.

Questão 3 de 10

Um ponteiro local é a única referência utilizável a um bloco alocado. Sua função retorna sem liberar o bloco nem salvar o ponteiro. Qual erro de memória resulta disso?
  1. Um vazamento de memória de uma alocação inacessível.
  2. Um uso após liberação causado pelo retorno da função.
  3. Um estouro de buffer que atinge o próximo bloco da área de alocação dinâmica.
  4. Uma dupla liberação do antigo bloco do ponteiro.
Mostrar respostaOcultar resposta
Resposta: A
A alocação na área de alocação dinâmica permanece ativa após o desaparecimento do ponteiro local. Sem uma referência salva, o programa não pode liberar nem reutilizar esse bloco por seu endereço de alocação. Retornar de uma função não libera, por si só, a memória da área de alocação dinâmica, portanto não se trata de uso após liberação.

Questão 4 de 10

Um programa aloca armazenamento para 12 inteiros de 4 bytes cada. Seu tipo de ponteiro ocupa 8 bytes. Quantos bytes sizeof(p) informa quando p contém o endereço da alocação?
  1. 4 bytes
  2. 48 bytes
  3. 12 bytes
  4. 8 bytes
Mostrar respostaOcultar resposta
Resposta: D
O operando de sizeof(p) é o objeto ponteiro, cujo tamanho informado é 8 bytes. A alocação contém 48 bytes, mas sizeof não segue um ponteiro para medir um bloco da área de alocação dinâmica. Usar aqui o tamanho da alocação confunde o ponteiro com seu destino.

Questão 5 de 10

Um processo tem base 18.000 e limite de tamanho 3.000. O que acontece quando ele lê do endereço virtual 2.750?
  1. Ele lê o byte físico 2.750.
  2. Ele falha porque 20.750 excede 3.000.
  3. Ele lê o byte físico 20.750.
  4. Ele lê o byte físico 15.250.
Mostrar respostaOcultar resposta
Resposta: C
O endereço virtual 2.750 é menor que o limite de 3.000 bytes, portanto o acesso é permitido. Somar a base 18.000 fornece o endereço físico 20.750. Comparar esse resultado físico com o limite expresso em tamanho de bytes rejeitaria incorretamente um endereço cujo deslocamento virtual cabe na região.

Questão 6 de 10

Com base 24.000 e limite de tamanho 4.500, o que acontece com um acesso ao endereço virtual 4.500?
  1. O hardware amplia a região em um byte.
  2. O hardware acessa o byte físico 28.500.
  3. O hardware rejeita o acesso por estar fora dos limites.
  4. O hardware acessa o byte físico 28.499.
Mostrar respostaOcultar resposta
Resposta: C
Uma região de 4.500 bytes contém os bytes virtuais de 0 a 4.499. O endereço virtual igual ao tamanho é o primeiro byte além dela, portanto o hardware gera uma exceção. Somar a base antes de aceitar a verificação não torna esse limite excluído um byte permitido.

Questão 7 de 10

Uma área de alocação dinâmica que cresce para cima começa no endereço virtual 2.048, tem tamanho 1.536 e base física 30.000. Para onde o endereço virtual 2.900 é traduzido?
  1. Byte físico 31.536.
  2. Byte físico 30.852.
  3. Byte físico 27.952.
  4. Byte físico 32.900.
Mostrar respostaOcultar resposta
Resposta: B
O deslocamento na área de alocação dinâmica é 852, obtido ao subtrair o início virtual 2.048 do endereço 2.900. Ele é menor que o tamanho 1.536, portanto somá-lo à base 30.000 resulta em 30.852. Somar o endereço virtual inteiro incluiria incorretamente o início virtual na relocação.

Questão 8 de 10

Um endereço segmentado usa dois bits seletores altos e dez bits de deslocamento baixos. Qual é o tamanho máximo em bytes da janela de um segmento?
  1. 1.024 bytes
  2. 1.023 bytes
  3. 4.096 bytes
  4. 256 bytes
Mostrar respostaOcultar resposta
Resposta: A
Dez bits de deslocamento representam 1.024 posições de bytes, numeradas de 0 a 1.023. Os dois bits seletores escolhem um segmento em vez de ampliar sua faixa de deslocamento. Usar os doze bits para obter 4.096 confunde o espaço de endereçamento completo com a janela de um segmento.

Questão 9 de 10

Uma área de alocação dinâmica tem lacunas livres de 22 e 34 bytes separadas por um bloco ativo. Os cabeçalhos são ignorados. Por que uma alocação contígua de 40 bytes pode falhar?
  1. Nenhuma das lacunas livres contém 40 bytes sozinha.
  2. As duas lacunas devem ser descartadas antes da reutilização.
  3. A requisição excede toda a capacidade livre somada.
  4. Os 56 bytes livres ficam dentro de blocos alocados.
Mostrar respostaOcultar resposta
Resposta: A
As lacunas somam 56 bytes, mas o alocador precisa de uma extensão ininterrupta de 40 bytes. A maior lacuna tem apenas 34 bytes, e o bloco ativo impede a união entre elas. Isso é fragmentação externa; os bytes livres estão fora das alocações, não são desperdício interno.

Questão 10 de 10

Uma área de alocação dinâmica de 512 bytes começa em 16.000. Cada alocação tem um cabeçalho de 16 bytes, sem arredondamento. O primeiro ajuste aloca áreas úteis de 48 e depois 64 bytes a partir da extremidade inferior. O primeiro bloco é liberado. Qual ponteiro é retornado para uma nova área útil de 56 bytes?
  1. 16.144
  2. 16.016
  3. 16.080
  4. 16.160
Mostrar respostaOcultar resposta
Resposta: D
Os dois primeiros blocos ocupam 64 e 80 bytes, portanto o espaço livre final começa em 16.144. O primeiro bloco liberado tem apenas 64 bytes no total e não pode conter uma área útil de 56 bytes mais seu cabeçalho. O novo bloco usa o espaço final, retornando 16.160; 16.144 é o endereço de seu cabeçalho.
Conjunto 2: Trocas de processos e decisões de alocação10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Qual região de um processo contém o endereço de retorno de uma chamada de função comum na organização usual?
  1. A região de código.
  2. A área de alocação dinâmica.
  3. A pilha.
  4. A região de dados estáticos.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

O limite da área de alocação dinâmica é 57.344. Uma chamada bem-sucedida a sbrk(4096) amplia a área. Qual é o valor retornado e qual é o novo limite?
  1. Retorno 61.440; novo limite 61.440.
  2. Retorno 57.344; novo limite 53.248.
  3. Retorno 57.344; novo limite 61.440.
  4. Retorno 4.096; novo limite 61.440.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um servidor libera vários blocos pequenos, mas seu uso de memória medido pelo sistema operacional permanece igual. Como isso pode ser normal?
  1. A biblioteca mantém as regiões para futuras requisições de blocos.
  2. Os ponteiros permanecem ativos porque o uso de memória não mudou.
  3. O sistema operacional só permite reutilizar os blocos após o processo terminar.
  4. Cada bloco liberado ainda deve conter uma alocação ativa.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

O processo R usa base 12.000 e o processo S usa base 28.000, ambos com limite 2.000. Após uma troca para S, um acesso permitido ao endereço virtual 640 alcança 12.640. Qual estado salvo não foi restaurado corretamente?
  1. O conteúdo da pilha do processo que saiu.
  2. O registrador base do processo que entrou.
  3. A largura do endereço virtual do processo que entrou.
  4. O tamanho limite do processo que entrou.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma posição de processo de 32 KB contém 3 KB de código, 5 KB de área de alocação dinâmica e 4 KB de pilha. Qual porcentagem da posição reservada está sem uso?
  1. 62,5%
  2. 37,5%
  3. 75%
  4. 20%
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Uma pilha que cresce para baixo tem uma janela de seleção de 4.096 bytes, base física 60.000 e tamanho atual 1.500. Seu campo de deslocamento é 3.200. O que acontece com uma leitura?
  1. Ela falha porque 3.200 excede 1.500.
  2. Ela alcança o byte físico 63.200.
  3. Ela alcança o byte físico 58.500.
  4. Ela alcança o byte físico 59.104.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Dois processos compartilham um segmento de código com permissão de leitura e execução na mesma base física. Um deles tenta escrever no segmento dentro dos limites. O que deve acontecer?
  1. O código dos dois processos muda nesse byte.
  2. Somente a cópia privada de código de quem escreve muda.
  3. Uma exceção de permissão bloqueia a escrita.
  4. A escrita é bem-sucedida porque seu deslocamento é permitido.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

As lacunas livres em ordem de endereço têm 44, 18, 70 e 32 bytes. Os cabeçalhos são ignorados; cada alocação usa a extremidade inferior. Qual política atende às requisições de 30 e depois 65 bytes, quando nenhum bloco é liberado entre elas: primeiro, melhor ou pior ajuste?
  1. O primeiro e o pior ajuste atendem; o melhor ajuste falha.
  2. O melhor e o pior ajuste atendem; o primeiro ajuste falha.
  3. As três políticas atendem às duas requisições.
  4. O primeiro e o melhor ajuste atendem; o pior ajuste falha.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

O próximo ajuste encontra lacunas de 16, 48, 24 e 40 bytes. Sua busca começa na quarta lacuna e volta ao início se necessário. Os cabeçalhos são ignorados. Qual lacuna atende a uma requisição de 30 bytes?
  1. A terceira lacuna, de 24 bytes.
  2. A segunda lacuna, de 48 bytes.
  3. A primeira lacuna, de 16 bytes.
  4. A quarta lacuna, de 40 bytes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um alocador de blocos parceiros começa com uma região livre de 32 KB e ignora os cabeçalhos. Ele aloca duas requisições de 6 KB nos menores deslocamentos disponíveis e depois libera a primeira. Qual é o maior bloco disponível imediatamente após isso?
  1. 24 KB
  2. 16 KB
  3. 32 KB
  4. 8 KB
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 3: Acompanhamento de limites e do estado do alocador10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um sistema verifica corretamente cada endereço virtual, mas entra no código do núcleo em toda leitura permitida. Qual objetivo da virtualização é mais diretamente prejudicado?
  1. Transparência da alocação.
  2. Eficiência de espaço.
  3. Isolamento de processos.
  4. Eficiência de tempo.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um bloco de 16 bytes da área de alocação dinâmica é liberado. Um ponteiro antigo é então usado para escrever dentro da área ainda mapeada do mesmo processo, e nenhuma falha imediata ocorre. O que melhor descreve essa escrita?
  1. Uma dupla liberação porque o endereço é reutilizado.
  2. Uma escrita válida porque a área permanece mapeada.
  3. Uso após liberação com comportamento indefinido.
  4. Um vazamento porque o bloco nunca foi liberado.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Em um modelo de segmentação, uma área de alocação dinâmica ocupa os bytes físicos de 10.000 a 13.999. Os próximos 1.000 bytes físicos estão ocupados. As lacunas livres em outros lugares têm 3.000 e 4.500 bytes. O alocador precisa ampliar essa área para 5.000 bytes. A extensão direta ou a relocação pode atender à necessidade?
  1. A relocação funciona na maior lacuna, de 4.500 bytes.
  2. Nenhuma das duas opções tem uma extensão contígua adequada.
  3. A extensão direta funciona porque são necessários mais 1.000 bytes.
  4. A relocação funciona porque as lacunas somam 7.500 bytes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um processo cujo limite é um tamanho ocupa os bytes físicos de 36.000 a 40.095. Uma instrução no endereço virtual 3.900 tenta ler do endereço virtual 4.096. O que acontece?
  1. A busca é bem-sucedida em 39.900; a leitura falha.
  2. Os dois acessos falham; cada um excede o limite de tamanho.
  3. Os dois acessos são bem-sucedidos na região atribuída.
  4. A busca é bem-sucedida em 39.900; a leitura usa 40.096.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um sistema operacional copia um processo pausado da base 22.000 para a base 47.000 sem alterar seu limite. Onde seu ponteiro virtual 960 deve chegar após a retomada?
  1. Byte físico 22.960.
  2. Byte físico 69.960.
  3. Byte físico 25.960.
  4. Byte físico 47.960.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um endereço virtual de 14 bits usa dois bits seletores e doze bits de deslocamento. O seletor 01 identifica uma área de alocação dinâmica que cresce para cima, com base 52.000 e tamanho 900. O que acontece com uma leitura no endereço virtual 0x1380?
  1. Ela falha porque 0x1380 excede o tamanho 900.
  2. Ela alcança o byte físico 52.896.
  3. Ela alcança o byte físico 52.900.
  4. Ela alcança o byte físico 56.992.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um sistema operacional tem lacunas livres de 5 KB, 11 KB e 7 KB, separadas por segmentos alocados. Ele deve posicionar um segmento de 13 KB sem mover segmentos ativos. Por que a requisição pode falhar?
  1. Cada segmento deve usar a mesma posição de tamanho fixo.
  2. A maior lacuna existente tem apenas 11 KB.
  3. As lacunas livres somadas fornecem menos de 13 KB.
  4. O segmento deve usar primeiro a menor lacuna.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Uma área de alocação dinâmica de 1.024 bytes no endereço 8.000 usa cabeçalhos de alocação de 16 bytes e nós livres de 16 bytes. Cada nó livre registra os bytes utilizáveis após ele. Duas áreas úteis de 80 bytes são alocadas a partir da extremidade inferior. Qual é o endereço e o tamanho utilizável do nó livre restante?
  1. Endereço 8.192; tamanho utilizável de 816 bytes.
  2. Endereço 8.192; tamanho utilizável de 832 bytes.
  3. Endereço 8.160; tamanho utilizável de 848 bytes.
  4. Endereço 8.224; tamanho utilizável de 800 bytes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um núcleo aloca repetidamente o mesmo tipo de objeto, e inicializar esse tipo tem custo elevado. Qual estrutura permite diretamente a reutilização de objetos inicializados?
  1. Um cache slab de objetos.
  2. Um cursor do próximo ajuste.
  3. Um registrador limite de tamanho.
  4. Um relocador estático.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Em uma região de blocos parceiros, qual é o deslocamento do parceiro de um bloco de 8 KB no deslocamento 24 KB relativo à região?
  1. 8 KB
  2. 0 KB
  3. 16 KB
  4. 32 KB
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 4: Explicação de falhas e preservação de mapeamentos10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Uma função contém um contador local estático e um contador local automático comum. O armazenamento de qual contador dura ao longo de chamadas sucessivas?
  1. O dos dois contadores locais.
  2. O de nenhum dos contadores locais.
  3. O do contador local estático.
  4. O do contador local automático.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Uma string em C contém 23 caracteres visíveis de um byte cada. Um programa aloca exatamente 23 bytes e copia os caracteres seguidos de um caractere nulo de término. O que dá errado?
  1. O primeiro caractere é uma leitura de memória não inicializada.
  2. O próprio ponteiro precisa de 24 bytes de armazenamento.
  3. O alocador recebe uma requisição de liberação inválida.
  4. O caractere de término é escrito além do bloco.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Dois processos reservam, cada um, uma posição de 24 KB com base e limite. Cada um usa 2 KB de código, 3 KB de área de alocação dinâmica e 1 KB de pilha. Quanto armazenamento físico suas posições reservadas consomem juntas?
  1. 12 KB
  2. 48 KB
  3. 24 KB
  4. 36 KB
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Uma reserva física de 48 KB contém três processos. Cada um tem uma extensão virtual de 16 KB, mas usa atualmente extensões contíguas de código, área de alocação dinâmica e pilha que somam 5 KB. Um quarto processo idêntico chega. Ignorando metadados e fragmentação, base e limite para o espaço inteiro e segmentação separada podem admiti-lo?
  1. Base e limite não pode; a segmentação pode.
  2. Ambos os esquemas podem admitir o quarto processo.
  3. A segmentação não pode; base e limite pode.
  4. Nenhum dos esquemas pode admitir o quarto processo.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma área de alocação dinâmica que cresce para cima começa no endereço virtual 8.192, com tamanho 2.000 e base física 40.000. O que acontece com uma leitura no endereço virtual 10.192?
  1. Ela alcança o byte físico 50.192.
  2. Ela alcança o byte físico 41.999.
  3. Ela falha no limite final exclusivo do segmento.
  4. Ela alcança o byte físico 42.000.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Uma área de alocação dinâmica que cresce para cima começa no endereço virtual 4.096 e tem tamanho 1.500. Sua base física muda de 20.000 para 46.000 após a relocação. Um acompanhamento mostra então o endereço virtual 5.300 alcançando o físico 51.300. Qual correção é necessária?
  1. Usar o endereço físico 47.204 após subtrair o início virtual da área.
  2. Usar o endereço físico 21.204 restaurando a base original.
  3. Manter o endereço físico 51.300 porque a relocação altera o endereço inteiro.
  4. Usar o endereço físico 50.096 substituindo o deslocamento pelo início.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um endereço de 14 bits usa dois bits seletores e doze bits de deslocamento. O seletor 11 identifica uma pilha que cresce para baixo, com base física 70.000 e tamanho atual 1.024. Leituras são permitidas. O que acontece no endereço virtual 15.360?
  1. Ele alcança o endereço físico 73.072 ao somar o campo positivo.
  2. Ele alcança o byte mais baixo da pilha, no endereço físico 68.976.
  3. Ele falha porque o módulo do deslocamento é igual ao tamanho.
  4. Ele alcança o endereço físico 68.975 como último byte permitido.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um alocador arredonda toda requisição de área útil para um múltiplo de 32 bytes e ignora os cabeçalhos. Que tipo e quantidade de desperdício uma requisição de 70 bytes cria?
  1. 32 bytes de fragmentação externa.
  2. 6 bytes de fragmentação interna.
  3. 26 bytes de fragmentação externa.
  4. 26 bytes de fragmentação interna.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Uma área de alocação dinâmica de 100 bytes tem blocos ativos nos bytes de 20 a 39 e de 60 a 79; todos os outros bytes estão livres. O primeiro bloco ativo é liberado e os blocos livres adjacentes são unidos por coalescência. Ignorando metadados, uma requisição de 65 bytes pode então ser atendida?
  1. Não; a maior extensão livre tem 40 bytes.
  2. Sim; há 80 bytes livres no total.
  3. Sim; liberar um bloco une toda a área.
  4. Não; a maior extensão livre tem 60 bytes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

As lacunas em ordem de endereço têm 26, 58 e 42 bytes. Os cabeçalhos são ignorados. O primeiro e o melhor ajuste alocam, cada um, 24 bytes e depois 40 bytes, sem liberações. Qual política pode então atender a uma requisição de 55 bytes?
  1. Nenhuma pode atender à requisição de 55 bytes.
  2. O primeiro ajuste pode; o melhor ajuste não pode.
  3. O melhor ajuste pode; o primeiro ajuste não pode.
  4. Ambas podem atender à requisição de 55 bytes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 5: Raciocínio combinado sobre tradução e alocação10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Uma arquitetura fornece a dois processos uma região física de código somente de leitura e regiões graváveis separadas. Quais objetivos da virtualização ela pode atender enquanto economiza espaço?
  1. A transparência exige código compartilhado gravável pelos dois.
  2. A eficiência de espaço exige remover todas as verificações de acesso.
  3. A transparência e o isolamento podem ser preservados.
  4. O isolamento é preservado apenas com cópias separadas do código.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Uma área de alocação dinâmica segmentada ocupa os bytes físicos de 20.000 a 23.999, seguidos de memória ocupada. Seu limite está no endereço virtual 10.000. O sistema operacional move a área para uma região livre de 6.000 bytes no endereço físico 40.000 e atende com sucesso a sbrk(1500). O que sbrk retorna e onde fica agora o primeiro byte existente da área?
  1. Retorno 11.500; primeiro byte existente em 40.000.
  2. Retorno 10.000; primeiro byte existente em 40.000.
  3. Retorno 41.500; primeiro byte existente em 40.000.
  4. Retorno 10.000; primeiro byte existente em 20.000.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um programa em modo usuário tenta definir seu registrador base para o início físico do núcleo. O que o processador deve fazer?
  1. Tratar a base solicitada como um ponteiro virtual comum.
  2. Instalar a base e confiar na verificação de tamanho existente.
  3. Gerar uma exceção pela operação privilegiada.
  4. Instalar a base apenas para a próxima leitura desse programa.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um endereço de 14 bits tem dois bits seletores e doze bits de deslocamento. O seletor 01 identifica uma área de alocação dinâmica que cresce para cima, com base 26.000 e tamanho 1.200. Seu tamanho aumenta depois para 1.400. Como muda uma leitura no endereço virtual 0x1500?
  1. Ela passa de uma falha para o byte físico 27.280.
  2. Ela continua permitida no byte físico 27.280.
  3. Ela continua falhando porque o seletor muda.
  4. Ela passa de uma falha para o byte físico 31.376.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Após pausar processos e compactar seus segmentos físicos, quais dados de mapeamento o sistema operacional deve corrigir para os segmentos que moveu?
  1. Suas bases físicas.
  2. Seus ponteiros virtuais.
  3. Suas permissões de acesso.
  4. Seus deslocamentos de código.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

A memória física tem o segmento ativo A nos bytes de 0 a 3.999, uma lacuna livre nos bytes de 4.000 a 5.999, o segmento ativo B nos bytes de 6.000 a 8.999 e uma lacuna livre nos bytes de 9.000 a 11.999. B pode ser movido. Para onde B pode ser movido para que um novo segmento de 4.500 bytes caiba depois?
  1. Mover B para os bytes de 5.000 a 7.999.
  2. Mover B para os bytes de 8.000 a 10.999.
  3. Mover B para os bytes de 7.000 a 9.999.
  4. Mover B para os bytes de 4.000 a 6.999.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Uma área de alocação dinâmica de 640 bytes começa em 24.000. As alocações têm cabeçalhos de 16 bytes e não há arredondamento. Áreas úteis de 64, 96 e 64 bytes são alocadas consecutivamente a partir da extremidade inferior. As duas primeiras são liberadas e unidas por coalescência. O primeiro ajuste atende então a uma área útil de 144 bytes. Qual ponteiro e qual sobra livre total dentro desse bloco unido resultam disso?
  1. Ponteiro 24.016; sobra de 32 bytes.
  2. Ponteiro 24.016; sobra de 48 bytes.
  3. Ponteiro 24.096; sobra de 32 bytes.
  4. Ponteiro 24.000; sobra de 48 bytes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

As lacunas em ordem de endereço têm 36, 64 e 48 bytes. Os cabeçalhos são ignorados. Chega uma requisição de 32 bytes e depois uma de 60 bytes. O próximo ajuste começa sua primeira busca na segunda lacuna e retoma na sobra dessa lacuna. Qual política pode atender às duas requisições: melhor ajuste ou esse próximo ajuste?
  1. Nenhuma das políticas pode atender às duas requisições.
  2. O melhor ajuste pode; o próximo ajuste não pode.
  3. Ambas as políticas podem atender às duas requisições.
  4. O próximo ajuste pode; o melhor ajuste não pode.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um alocador de blocos parceiros ignora a sobrecarga em uma região de 32 KB. Ele aloca 7 KB no deslocamento 0, outros 7 KB no deslocamento 8 KB e 12 KB no deslocamento 16 KB. As duas alocações de 7 KB são liberadas. Por que ele não consegue atender a uma nova requisição de 20 KB?
  1. As duas alocações liberadas fornecem apenas 14 KB, portanto não podem formar um bloco de 16 KB.
  2. O bloco necessário de 32 KB não pode se formar enquanto seu parceiro superior de 16 KB estiver ativo.
  3. Faltam apenas 4 KB ao bloco disponível de 16 KB para atingir o tamanho necessário.
  4. Os blocos livres inferiores permanecem separados porque a união de parceiros exige uma nova divisão.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um processo com base e limite tem base física 11.500. Qual endereço físico corresponde ao seu endereço virtual permitido 700?
  1. 10.800
  2. 700
  3. 11.500
  4. 12.200
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Travou em uma questão sua? Ajuda com Tarefas

Termos-Chave

73 Termos-Chave, cada um com sua definição

Á

Área de alocação dinâmica
A área de alocação dinâmica é uma região de um processo usada para blocos requisitados durante a execução, cujos tempos de vida são gerenciados por meio de alocação e liberação.
Um objeto na área de alocação dinâmica pode durar mais que a função que originalmente requisitou seu armazenamento.
Área útil
Uma área útil é a parte de um bloco alocado disponível ao programa, excluindo o cabeçalho e outros registros do alocador.
Uma área útil de 96 bytes com um cabeçalho de dezesseis bytes ocupa pelo menos 112 bytes da região gerenciada.

A

Alocação ativa
Uma alocação ativa é um bloco que ainda pertence ao programa e não foi liberado, cujo endereço retornado um alocador comum de C deve preservar.
Um bloco ativo entre lacunas livres impede que o alocador as una por coalescência através dele.
Alocador de blocos parceiros
Um alocador de blocos parceiros gerencia blocos com tamanhos em potências de dois, dividindo-os em metades iguais e unindo um bloco liberado apenas a seu parceiro correspondente livre.
Uma requisição de 10 KB recebe um bloco de 16 KB, deixando 6 KB sem uso dentro dessa alocação.
Alocador slab
Um alocador slab mantém caches de tipos de objetos recorrentes em slabs, permitindo a reutilização rápida de objetos e reduzindo o trabalho de inicialização repetida.
Um núcleo pode obter outro descritor de processo de seu cache de objetos em vez de construir um novo.
Arena
Uma arena é uma região do alocador gerenciada separadamente, usada junto com outras arenas para reduzir a disputa por uma única trava de alocação compartilhada.
Threads que usam arenas diferentes podem atender a muitas requisições sem esperar pela mesma trava do alocador.
Armazenamento estático
O armazenamento estático é o armazenamento de variáveis globais e locais estáticas que dura toda a execução do programa, independentemente das chamadas individuais.
Um contador local estático mantém seu valor entre chamadas em vez de desaparecer com cada quadro de pilha.
Arredondamento do tamanho de alocação
O arredondamento do tamanho de alocação eleva o tamanho solicitado a um tamanho ou alinhamento disponível, deixando qualquer capacidade excedente dentro do bloco alocado.
Arredondar 21 bytes para um bloco de 32 bytes deixa 11 bytes de desperdício interno.

B

Bits de proteção
Os bits de proteção especificam operações permitidas em uma região, como leitura, escrita ou execução, e são verificados separadamente dos limites.
Um deslocamento válido no código ainda causa uma falha quando o processo tenta escrever em uma área com permissão de leitura e execução.
Bloco de controle de processo
Um bloco de controle de processo é um registro do sistema operacional que contém o estado de execução salvo de um processo, incluindo valores de tradução quando o processo está inativo.
O sistema operacional restaura a base e o limite salvos do próximo processo a partir de seu bloco de controle de processo.
Bloco parceiro
Um bloco parceiro é o bloco de mesmo tamanho criado pela divisão de um bloco pai, identificável aplicando XOR ao deslocamento de seu parceiro e ao tamanho do bloco.
Dois blocos adjacentes de 8 KB não podem ser unidos a menos que sejam os parceiros de uma mesma divisão de 16 KB.
brk
brk define o limite final da área tradicional de alocação dinâmica em um endereço especificado, permitindo que o alocador altere o tamanho dessa região.
O alocador controla os registros do limite, portanto o código da aplicação deve requisitar blocos por meio da biblioteca.

C

Cabeçalho de alocação
Um cabeçalho de alocação contém metadados armazenados antes de uma área útil retornada, normalmente registrando o tamanho para que o alocador possa processar uma chamada posterior a free.
Com um cabeçalho de dezesseis bytes, um ponteiro para a área útil em 8.016 leva de volta aos metadados em 8.000.
calloc
calloc é uma função de alocação da biblioteca C que fornece armazenamento preenchido com bytes de valor zero, ao contrário do armazenamento não zerado retornado por malloc.
Um buffer obtido por calloc começa com bytes de valor zero antes que o programa escreva quaisquer dados.
Campo de deslocamento
Um campo de deslocamento é a parte de um endereço segmentado que localiza um byte dentro de uma janela de seleção, antes de qualquer ajuste para crescimento descendente.
Um campo de doze bits permite 4.096 posições mesmo que o segmento selecionado use atualmente menos bytes.
Coalescência de blocos livres
A coalescência de blocos livres une blocos livres adjacentes em um bloco livre maior sem mover alocações ativas, reduzindo as entradas separadas da lista de blocos livres.
Liberar um bloco intermediário pode permitir que duas lacunas vizinhas formem uma única extensão utilizável para alocação.
Compactação
A compactação move regiões físicas ativas para ficarem juntas e atualiza seus mapeamentos para combinar a capacidade livre dispersa em uma lacuna maior.
O sistema operacional copia segmentos e altera suas bases enquanto os programas continuam usando os mesmos endereços virtuais.
Compartilhamento de código
O compartilhamento de código permite que processos executem uma única cópia física de instruções imutáveis enquanto mantêm separados seus estados graváveis.
Dois processos podem usar a mesma base de código somente de leitura com bases diferentes para suas áreas de alocação dinâmica e pilhas.
Contenção de travas
A contenção de travas ocorre quando threads concorrentes esperam para acessar o mesmo estado protegido do alocador, limitando o progresso paralelo das alocações.
Caches locais e múltiplas arenas reduzem o número de alocações que precisam de uma única trava comum.

D

Deslocamento negativo
Um deslocamento negativo mede um acesso a um segmento que cresce para baixo em relação ao seu limite superior e é obtido subtraindo-se o tamanho completo da janela.
Um campo de 3.000 em uma janela de pilha de 4.096 bytes fornece um deslocamento de −1.096.
Deslocamento no segmento
Um deslocamento no segmento localiza um byte em relação à origem virtual de seu segmento; na tradução de um segmento que cresce para cima, o deslocamento verificado é somado à base física.
O byte virtual 5.100 em uma área de alocação dinâmica que começa em 4.096 tem deslocamento 1.004 antes da relocação física.
Direção de crescimento
A direção de crescimento de um segmento registra se sua região válida se estende para cima a partir de um primeiro byte ou para baixo a partir de um limite superior.
A direção da pilha muda a forma como o hardware interpreta o campo baixo do endereço antes de somar a base.
Divisão de blocos
A divisão de blocos divide um bloco livre em uma parte alocada e uma parte livre restante, preservando a sobra final para requisições posteriores.
Uma requisição de 24 bytes retirada de um bloco de 80 bytes deixa 56 bytes quando os cabeçalhos são ignorados.
Dupla liberação
Uma dupla liberação é uma tentativa de liberar novamente a mesma alocação depois que ela já foi liberada, violando as regras de posse do alocador.
Chamar free duas vezes por meio de ponteiros copiados para um mesmo bloco pode corromper o estado da biblioteca de alocação.

E

Endereço físico
Um endereço físico identifica uma localização no hardware de memória, alcançada após a tradução de um acesso à memória virtual de um processo.
O endereço virtual 800 de dois processos pode ser traduzido para endereços físicos diferentes na mesma máquina.
Endereço virtual
Um endereço virtual identifica um byte na visão da memória de um processo e é traduzido antes que o processador acesse a memória física.
Um ponteiro impresso por um programa em C mostra um endereço virtual mesmo quando o sistema operacional move seu armazenamento físico.
Espaço de endereçamento
Um espaço de endereçamento é a visão da memória disponível a um processo em execução, incluindo regiões para instruções, dados, blocos da área de alocação dinâmica e chamadas de função.
Dois processos podem usar a mesma organização do espaço de endereçamento enquanto seus bytes ocupam regiões físicas diferentes.
Espaço de endereçamento esparso
Um espaço de endereçamento esparso tem grandes espaços virtuais não usados entre regiões usadas, tornando a alocação física de toda a extensão um desperdício.
Separar a área de alocação dinâmica e a pilha em segmentos independentes evita reservar o espaço vazio entre elas.
Estouro de buffer
Um estouro de buffer é uma escrita além do fim alocado de um buffer, que pode corromper dados vizinhos ou registros do alocador.
Copiar uma string para um espaço sem um byte para seu caractere nulo de término pode causar um estouro de buffer.

F

Falha de segmentação
Uma falha de segmentação é um acesso inválido à memória informado pelo sistema; o nome permanece mesmo quando a máquina não usa segmentação clássica.
Uma violação de permissão pode produzir uma falha de segmentação mesmo quando seu deslocamento está dentro da região.
Fragmentação externa
A fragmentação externa deixa a memória livre em lacunas separadas pequenas demais para uma requisição contígua, apesar de haver capacidade livre suficiente no total.
Lacunas de 7 KB e 9 KB não podem conter um único segmento de 12 KB, embora somem 16 KB.
Fragmentação interna
A fragmentação interna é a capacidade não usada dentro de uma região alocada, causada pela reserva de mais espaço do que seu conteúdo útil exige.
Uma posição de processo de 16 KB que contém 4 KB de conteúdo útil desperdiça 12 KB dentro de sua alocação.
free
free é uma função da biblioteca C que devolve um bloco alocado ativo ao alocador; passar NULL é permitido e não tem efeito.
O alocador pode reutilizar um bloco liberado mesmo que o processo mantenha o mesmo uso de memória medido pelo sistema operacional.

G

Gerenciamento de espaço livre
O gerenciamento de espaço livre controla os blocos disponíveis e escolhe onde alocar requisições, na escala da área de alocação dinâmica de um processo ou das regiões físicas do sistema operacional.
Um alocador deve encontrar um único bloco suficiente mesmo quando seu total de bytes livres excede a requisição.

I

Instrução privilegiada
Uma instrução privilegiada é uma operação permitida apenas em modo núcleo, impedindo que programas de usuário alterem o estado protegido da máquina.
Uma tentativa de atualizar o registrador base em modo usuário gera uma exceção em vez de alterar o mapeamento.
Isolamento
O isolamento é a separação imposta entre processos para que um acesso não autorizado não possa ler nem corromper outro processo ou o núcleo.
O hardware rejeita um acesso de um editor fora de sua região permitida antes que ele danifique um processo vizinho.

L

Leitura de memória não inicializada
Uma leitura de memória não inicializada usa dados armazenados antes que o programa tenha definido seu valor, como quando lê bytes não zerados retornados por malloc.
Alocar espaço suficiente para um inteiro não dá a esse inteiro um valor inicial significativo.
Limite da área de alocação dinâmica
O limite da área de alocação dinâmica é a fronteira virtual imediatamente após o fim da área tradicional, movida quando essa região é ampliada ou reduzida.
Se o limite for 30.000, o byte 30.000 estará fora da área de alocação dinâmica até que a fronteira avance para um endereço maior.
Lista de blocos livres
Uma lista de blocos livres registra blocos disponíveis e seus tamanhos, com ligações ou outra estrutura que permite ao alocador encontrar e atualizar entradas.
Após a divisão de um bloco, sua parte final não usada permanece na lista de blocos livres se puder conter um nó livre utilizável.
Listas segregadas
As listas segregadas mantêm reservas separadas para tamanhos de bloco selecionados, de modo que requisições de tamanhos comuns possam ser atendidas sem uma busca geral.
Uma reserva de blocos de 64 bytes atende rapidamente a requisições repetidas dessa classe de tamanho.

M

malloc
malloc é uma função da biblioteca C que requisita um bloco de tamanho especificado em bytes e retorna seu endereço, ou NULL em caso de falha, sem zerar seu conteúdo.
Uma requisição para seis inteiros usa malloc(6 * sizeof(int)) para considerar o tamanho do elemento.
Mapeamento anônimo
Um mapeamento anônimo é uma região de memória virtual preenchida com zeros e criada sem associar seu armazenamento a um arquivo.
Um alocador pode obter uma grande região separada por meio de uma requisição anônima a mmap.
Máscara de bits
Uma máscara de bits seleciona posições de bits escolhidas com uma operação bit a bit, permitindo que o hardware ou o código separe campos de endereço.
Aplicar va & 0x0FFF mantém doze bits baixos enquanto zera os dois bits de segmento de um endereço de quatorze bits.
Mecanismo
Um mecanismo é a implementação que realiza uma operação, como o hardware verificar limites e somar uma base nos acessos à memória.
Alterar a regra de seleção de lacunas não exige substituir o mecanismo de tradução por hardware.
Melhor ajuste
O melhor ajuste seleciona o menor bloco livre suficientemente grande para uma requisição, limitando a sobra imediata, mas às vezes criando sobras minúsculas.
Para lacunas de 60, 28 e 44 bytes, uma requisição de 25 bytes usa a lacuna de 28 bytes no melhor ajuste.
munmap
munmap remove uma região mapeada do espaço de endereçamento de um processo, diferentemente da devolução de um bloco pequeno a uma reserva da biblioteca para reutilização.
Liberar uma alocação grande mapeada separadamente pode permitir que o alocador remova o mapeamento correspondente.

N

Nó da lista de blocos livres embutido no bloco
Um nó da lista de blocos livres embutido no bloco armazena o tamanho e as ligações de um bloco livre dentro do próprio bloco, reutilizando a memória gerenciada para os registros.
Depois que um bloco livre é dividido, os primeiros bytes de sua parte livre final contêm seu nó em vez de uma alocação separada fora da área de alocação dinâmica.

P

Permissão de leitura e execução
A permissão de leitura e execução permite que os bytes de uma região sejam lidos e executados como instruções, enquanto nega escritas que os modificariam.
Um segmento de código compartilhado permite buscas de instrução, mas rejeita uma tentativa de escrita em seus bytes.
Pilha
Uma pilha é uma região usada para o estado das chamadas de função, incluindo endereços de retorno e variáveis locais comuns no modelo usual de execução.
Retornar de uma função libera seu quadro de pilha, mas não libera um bloco da área de alocação dinâmica que ela alocou.
Pior ajuste
O pior ajuste seleciona o maior bloco livre, buscando deixar uma sobra útil, mas podendo consumir uma lacuna necessária a requisições grandes posteriores.
Uma requisição pequena colocada na única lacuna grande pode fazer a próxima alocação maior falhar.
Política
Uma política é uma regra para escolher entre ações possíveis, como qual região física livre deve conter um processo recém-criado.
Escolher a menor lacuna suficiente é uma política de alocação aplicada por um gerenciador de memória.
Ponteiro pendente
Um ponteiro pendente é um ponteiro para um armazenamento cujo tempo de vida terminou, como um bloco da área de alocação dinâmica já devolvido ao alocador.
Ler por meio de um ponteiro antigo após a liberação de seu bloco é um erro de uso após liberação.
Primeiro ajuste
O primeiro ajuste escolhe o primeiro bloco suficiente na ordem da lista e interrompe a busca, portanto sua escolha depende de como a lista está ordenada.
Com lacunas de 60, 28 e 44 bytes ordenadas por endereço, uma requisição de 25 bytes usa a lacuna de 60 bytes.
Próximo ajuste
O próximo ajuste busca um bloco suficiente a partir de uma posição salva, voltando ao início da lista em vez de reiniciar a busca ali.
Começar uma busca de próximo ajuste na terceira lacuna de uma lista em vez de na primeira pode mudar sua escolha mesmo quando os tamanhos livres permanecem iguais.

R

realloc
realloc é uma função da biblioteca C que altera o tamanho de um bloco alocado e pode mover seu conteúdo para um bloco em outro endereço.
Um buffer em crescimento pode ser movido quando seu bloco atual não tem espaço disponível imediatamente após ele.
Região contígua
Uma região contígua é um intervalo ininterrupto de endereços de bytes vizinhos, necessário para um processo inteiro no mecanismo simples de base e limite.
Lacunas físicas separadas não podem conter conjuntamente uma região que precisa ser contígua.
Registrador base
Um registrador base contém o endereço físico inicial de uma região na relocação comum para cima, ao qual são somados os deslocamentos virtuais válidos.
Com base física 12.000, o deslocamento virtual 200 alcança o byte físico 12.200 após uma verificação bem-sucedida.
Registrador limite
Um registrador limite delimita uma região de processo e, neste modelo, contém seu tamanho em bytes; os endereços virtuais válidos devem ser estritamente menores que esse tamanho.
O limite 4.096 aceita o byte virtual 4.095, mas rejeita um acesso ao endereço virtual 4.096.
Relocação dinâmica
A relocação dinâmica traduz endereços durante a execução, permitindo que o sistema operacional mova o armazenamento físico enquanto preserva os valores dos ponteiros virtuais.
Mover um processo pausado e alterar sua base faz seus ponteiros existentes alcançarem os bytes copiados.
Relocação estática
A relocação estática reescreve endereços ao carregar um programa para corresponder à sua localização física, sem, por si só, impor proteção de acesso à memória.
Mudar a localização de carregamento exige que o carregador reescreva os endereços incorporados para a nova posição.

S

sbrk
sbrk altera o limite da área de alocação dinâmica pelo incremento de bytes solicitado e retorna o limite anterior em caso de sucesso; um incremento zero informa o limite atual.
Uma chamada bem-sucedida a sbrk(1024) com limite em 20.000 retorna 20.000 e deixa o novo limite em 21.024.
Segmentação
A segmentação traduz regiões lógicas independentemente usando o estado de cada segmento, permitindo que a localização física seja diferente da organização virtual.
Um espaço virtual de 16 KB pode usar apenas 7 KB de memória física para seus três segmentos atualmente usados.
Segmentação de granularidade fina
A segmentação de granularidade fina divide um espaço de endereçamento em muitas regiões menores protegidas independentemente, descritas por uma tabela de segmentos.
Uma estrutura de dados separada pode ter suas próprias regras de compartilhamento e acesso em uma arquitetura de granularidade fina.
Segmentação de granularidade grossa
A segmentação de granularidade grossa divide um espaço de endereçamento em poucas regiões grandes, normalmente código, área de alocação dinâmica e pilha, com estados de tradução separados.
Um pequeno grupo de pares de registradores de segmento pode descrever a organização clássica de processo em três regiões.
Segmento
Um segmento é uma região lógica contígua de um espaço de endereçamento com estado de tradução independente, como uma região de código, área de alocação dinâmica ou pilha.
O segmento da área de alocação dinâmica pode ser movido sem exigir que o segmento de código seja movido para a mesma região física.
Seleção implícita de segmento
A seleção implícita de segmento escolhe o estado de tradução pela forma como um endereço foi gerado, como em uma busca de instrução ou no uso do ponteiro de pilha.
Uma busca usa a tradução do código sem precisar de um campo explícito de número de segmento em seu endereço.
Seletor de segmento
Um seletor de segmento identifica qual estado de tradução de segmento se aplica a um endereço virtual explícito, separadamente de seu campo de deslocamento.
Em uma divisão de quatorze bits, os bits iniciais 01 podem selecionar a área de alocação dinâmica enquanto os doze bits baixos localizam seu byte.

T

Tabela de segmentos
Uma tabela de segmentos armazena informações de tradução e proteção para muitos segmentos, permitindo mais regiões do que alguns pares fixos de registradores.
A segmentação de granularidade fina consulta em uma tabela a base, o tamanho e os controles de acesso de cada região selecionada.
Transparência
A transparência é a propriedade que permite a um programa usar sua própria visão da memória sem gerenciar a localização física ou o compartilhamento por trás dela.
Um processo mantém os mesmos ponteiros virtuais depois que o sistema operacional realoca sua memória física.
Tratador de exceções
Um tratador de exceções é um código do sistema operacional executado depois que o hardware detecta um evento como um endereço de memória inválido ou uma instrução proibida.
Uma violação de limites transfere o controle ao tratador registrado, que geralmente encerra o processo.
Troca de contexto
Uma troca de contexto substitui o estado ativo da CPU do processo em execução pelo estado salvo de outro processo, incluindo seus valores de tradução de memória.
Restaurar os registradores gerais do próximo processo sem sua base deixaria ativa a visão errada da memória.

U

Unidade de gerenciamento de memória
A unidade de gerenciamento de memória é o hardware do processador que traduz endereços virtuais e verifica regras de acesso usando o estado instalado pelo sistema operacional.
A MMU traduz uma busca de instrução sem chamar uma rotina do sistema operacional para cada instrução.

V

Vazamento de memória
Um vazamento de memória ocorre quando o armazenamento alocado deixa de ser liberado quando necessário, muitas vezes porque o programa perde seu último ponteiro utilizável para ele.
Uma função que retorna sem preservar nem liberar seu único ponteiro para a área de alocação dinâmica deixa um bloco inacessível.

Sobre esta aula

Por StudeliRelatar um erro

Crie seus próprios Materiais de Estudo

Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.

Começar