O que realmente significa “Memória alocada em tempo de compilação”?


159

Em linguagens de programação como C e C ++, as pessoas geralmente se referem à alocação de memória estática e dinâmica. Entendo o conceito, mas a frase "Toda a memória foi alocada (reservada) durante o tempo de compilação" sempre me confunde.

A compilação, como eu a entendo, converte código C / C ++ de alto nível em linguagem de máquina e gera um arquivo executável. Como a memória é "alocada" em um arquivo compilado? A memória não é sempre alocada na RAM com todo o material de gerenciamento de memória virtual?

A alocação de memória por definição não é um conceito de tempo de execução?

Se eu criar uma variável alocada estaticamente de 1 KB no meu código C / C ++, isso aumentará o tamanho do executável na mesma quantidade?

Esta é uma das páginas em que a frase é usada sob o título "Alocação estática".

De volta ao básico: alocação de memória, uma caminhada pela história


o código e os dados são totalmente segregados na maioria das arquiteturas modernas. enquanto os arquivos de origem contêm os dois dados de código no mesmo local, a lixeira possui apenas referências aos dados. Isso significa que os dados estáticos na origem são resolvidos apenas como referências.
Cholthi Paul Ttiopic

Respostas:


184

Memória alocada em tempo de compilação significa que o compilador resolve em tempo de compilação, onde certas coisas serão alocadas dentro do mapa de memória do processo.

Por exemplo, considere uma matriz global:

int array[100];

O compilador sabe em tempo de compilação o tamanho da matriz e o tamanho de um int, portanto, conhece todo o tamanho da matriz em tempo de compilação. Além disso, uma variável global tem duração de armazenamento estático por padrão: é alocada na área de memória estática do espaço de memória do processo (seção .data / .bss). Dadas essas informações, o compilador decide durante a compilação em qual endereço da área de memória estática a matriz será .

É claro que os endereços de memória são endereços virtuais. O programa assume que ele possui todo o seu próprio espaço de memória (de 0x00000000 a 0xFFFFFFFF, por exemplo). É por isso que o compilador pode fazer suposições como "Ok, a matriz estará no endereço 0x00A33211". No tempo de execução, esses endereços são traduzidos para endereços reais / de hardware pelo MMU e pelo SO.

Valor inicializado armazenamento estático coisas são um pouco diferentes. Por exemplo:

int array[] = { 1 , 2 , 3 , 4 };

Em nosso primeiro exemplo, o compilador decidiu apenas onde a matriz será alocada, armazenando essas informações no executável.
No caso de itens inicializados por valor, o compilador também injeta o valor inicial da matriz no executável e adiciona código que informa ao carregador do programa que após a alocação da matriz no início do programa, a matriz deve ser preenchida com esses valores.

Aqui estão dois exemplos do assembly gerado pelo compilador (GCC4.8.1 com destino x86):

Código C ++:

int a[4];
int b[] = { 1 , 2 , 3 , 4 };

int main()
{}

Conjunto de saída:

a:
    .zero   16
b:
    .long   1
    .long   2
    .long   3
    .long   4
main:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    $0, %eax
    popq    %rbp
    ret

Como você pode ver, os valores são injetados diretamente na montagem. Na matriz a, o compilador gera uma inicialização zero de 16 bytes, porque o Padrão diz que itens armazenados estáticos devem ser inicializados como zero por padrão:

8.5.9 (Inicializadores) [Nota]:
Todo objeto com duração de armazenamento estático é inicializado com zero na inicialização do programa antes de qualquer outra inicialização. Em alguns casos, a inicialização adicional é feita posteriormente.

Eu sempre sugiro que as pessoas desmontem seu código para ver o que o compilador realmente faz com o código C ++. Isso se aplica das classes / duração do armazenamento (como esta pergunta) às otimizações avançadas do compilador. Você pode instruir seu compilador a gerar o assembly, mas existem ferramentas maravilhosas para fazer isso na Internet de maneira amigável. O meu favorito é o GCC Explorer .


2
Obrigado. Isso esclarece muito. Portanto, o compilador gera algo equivalente a "reservar memória de 0xABC a 0xXYZ para a matriz variável [] etc." e então o carregador usa isso para alocá-lo realmente antes de executar o programa?
Talha disse

1
@TalhaSayed exatamente. Veja a edição para ver o exemplo
Manu343726

2
@Ecko eu simplifiquei as coisas. É apenas uma menção sobre o programa que funciona através da memória virtual, mas como a questão não é sobre memória virtual, não estendi o tópico. Eu estava apenas apontando que o compilador pode fazer suposições sobre endereços de memória em tempo de compilação, graças à memória virtual.
precisa saber é o seguinte

2
@Secko sim. mmm "gerado" é um termo melhor, eu acho.
precisa saber é o seguinte

2
"Está alocado na área mamária estática do espaço de memória do processo" Leitura que alocou algumas áreas mamárias estáticas no meu espaço de memória do processo.
Radiodef 25/01

27

A memória alocada no tempo de compilação significa simplesmente que não haverá alocação adicional no tempo de execução - nenhuma chamada para malloc, novos ou outros métodos de alocação dinâmica. Você terá uma quantidade fixa de uso de memória, mesmo que não precise de toda essa memória o tempo todo.

A alocação de memória por definição não é um conceito de tempo de execução?

A memória não está em uso antes do tempo de execução, mas imediatamente antes da execução iniciar sua alocação é tratada pelo sistema.

Se eu criar uma variável alocada estaticamente de 1 KB no meu código C / C ++, isso aumentará o tamanho do executável na mesma quantidade?

Simplesmente declarar a estática não aumentará o tamanho do seu executável mais do que alguns bytes. Declará-lo com um valor inicial diferente de zero será (para manter esse valor inicial). Em vez disso, o vinculador simplesmente adiciona essa quantidade de 1 KB ao requisito de memória que o carregador do sistema cria para você imediatamente antes da execução.


1
se eu escrever static int i[4] = {2 , 3 , 5 ,5 }aumentará pelo tamanho do executável em 16 bytes. Você disse "Simplesmente declarar a estática não aumentará o tamanho do seu executável em mais de alguns bytes. Declará-lo com um valor inicial diferente de zero" Declará-lo com valor inicial será o que isso significa.
Suraj Jain

Seu executável possui duas áreas para dados estáticos - uma para estática não inicializada e outra para estática inicializada. A área não inicializada é realmente apenas uma indicação de tamanho; quando o programa é executado, esse tamanho é usado para aumentar a área de armazenamento estático, mas o próprio programa não precisa conter nada além da quantidade de dados não inicializados usados. Para estática inicializada, seu programa deve conter não apenas o tamanho de (cada) estática, mas também para o que é inicializado. Assim, no seu exemplo, seu programa terá 2, 3, 5 e 5.
Mah

Sua implementação é definida como onde é colocada / como é alocada, mas não tenho certeza se entendi a necessidade de saber.
mah

23

A memória alocada em tempo de compilação significa que, quando você carrega o programa, alguma parte da memória será imediatamente alocada e o tamanho e a posição (relativa) dessa alocação são determinados em tempo de compilação.

char a[32];
char b;
char c;

Essas 3 variáveis ​​são "alocadas no momento da compilação", significa que o compilador calcula seu tamanho (que é fixo) no momento da compilação. A variável aserá um deslocamento na memória, digamos, apontando para o endereço 0, bapontando para o endereço 33 e c34 (supondo que não haja otimização do alinhamento). Portanto, alocar 1 KB de dados estáticos não aumentará o tamanho do seu código , pois apenas mudará um deslocamento dentro dele. O espaço real será alocado no momento do carregamento .

A alocação de memória real sempre acontece em tempo de execução, porque o kernel precisa acompanhá-lo e atualizar suas estruturas de dados internas (quanta memória é alocada para cada processo, páginas e assim por diante). A diferença é que o compilador já sabe o tamanho de cada dado que você vai usar e isso é alocado assim que o programa é executado.

Lembre-se também de que estamos falando de endereços relativos . O endereço real onde a variável será localizada será diferente. No momento do carregamento, o kernel reservará alguma memória para o processo, digamos no endereço x, e todos os endereços codificados contidos no arquivo executável serão incrementados em xbytes, de modo que a variável ano exemplo esteja no endereço x, b no endereço x+33e em breve.


17

Adicionar variáveis ​​na pilha que ocupam N bytes não aumenta (necessariamente) o tamanho da lixeira em N bytes. Na verdade, ele adicionará apenas alguns bytes na maioria das vezes.
Vamos começar com um exemplo de como a adição de um 1000 caracteres ao seu código irá aumentar o tamanho do bin de uma forma linear.

Se o 1k for uma sequência de mil caracteres, declarada como tal

const char *c_string = "Here goes a thousand chars...999";//implicit \0 at end

e você era então vim your_compiled_bin, na verdade seria capaz de ver essa corda na lixeira em algum lugar. Nesse caso, sim: o executável será 1 k maior, porque contém a string na íntegra.
Se, no entanto, você alocar uma matriz de ints, chars ou longs na pilha e atribuí-la em um loop, algo nesse sentido

int big_arr[1000];
for (int i=0;i<1000;++i) big_arr[i] = some_computation_func(i);

então, não: não aumentará a lixeira ... por 1000*sizeof(int)
Alocação em tempo de compilação significa o que você agora entende (com base em seus comentários): a lixeira compilada contém informações que o sistema precisa para saber quanta memória qual função / bloco precisará quando for executado, juntamente com informações sobre o tamanho da pilha que seu aplicativo exige. É isso que o sistema alocará quando executar sua lixeira e seu programa se tornar um processo (bem, a execução de sua lixeira é o processo que ... bem, você entendeu o que estou dizendo).
Obviamente, não estou pintando a imagem completa aqui: a lixeira contém informações sobre o tamanho da pilha que a lixeira realmente precisará. Com base nessas informações (entre outras coisas), o sistema reservará um pedaço de memória, chamado pilha, sobre o qual o programa fica livre. A memória da pilha ainda é alocada pelo sistema, quando o processo (o resultado da execução da sua posição) é iniciado. O processo gerencia a memória da pilha para você. Quando uma função ou loop (qualquer tipo de bloco) é invocado / executado, as variáveis ​​locais para esse bloco são enviadas para a pilha e são removidas (a memória da pilha é "liberada", por assim dizer) para ser usada por outros funções / blocos. Então declarandoint some_array[100]adicionará apenas alguns bytes de informações adicionais à lixeira, informando ao sistema que a função X exigirá 100*sizeof(int)+ algum espaço extra de contabilidade.


Muito obrigado. Mais uma pergunta: as variáveis ​​locais para funções também são alocadas da mesma maneira durante o tempo de compilação?
Talha disse

@TalhaSayed: Sim, foi o que eu quis dizer quando disse: "informações que o sistema precisa para saber quanta memória qual função / bloco exigirá". No momento em que você chama uma função, o sistema alocará a memória necessária para essa função. No momento em que a função retornar, essa memória será liberada novamente.
Elias Van Ootegem

Quanto aos comentários no seu código C: não é realmente / necessariamente o que acontece. Por exemplo, a string provavelmente será alocada apenas uma vez, no momento da compilação. Portanto, nunca é "liberado" (também acho que a terminologia geralmente é usada apenas quando você aloca algo dinamicamente), inão é "liberado" ou também. Se iresidisse na memória, seria empurrado para a pilha, algo que não é liberado no sentido da palavra, desconsiderando isso iou que cserá mantido em registros o tempo todo. Obviamente, tudo isso depende do compilador, o que significa que não é tão preto e branco.
Phant0m

@ phant0m: Eu nunca disse que a string está alocada na pilha, apenas o ponteiro também seria, a própria string residiria na memória somente leitura. Eu sei que a memória associada às variáveis ​​locais não é liberada no sentido de free()chamadas, mas a memória da pilha que elas usam é gratuita para uso de outras funções quando a função listada retorna. I removido o código, uma vez que pode ser confuso para alguns
Elias Van Ootegem

Ah entendo. Nesse caso, considere meu comentário como "fiquei confuso com sua redação".
usar o seguinte comando

16

Em muitas plataformas, todas as alocações globais ou estáticas em cada módulo serão consolidadas pelo compilador em três ou menos alocações consolidadas (uma para dados não inicializados (geralmente chamados de "bss"), outra para dados graváveis ​​inicializados (geralmente denominados "dados" ) e uma para dados constantes ("const")), e todas as alocações globais ou estáticas de cada tipo em um programa serão consolidadas pelo vinculador em uma global para cada tipo. Por exemplo, supondo que intsejam quatro bytes, um módulo tem as seguintes alocações estáticas:

int a;
const int b[6] = {1,2,3,4,5,6};
char c[200];
const int d = 23;
int e[4] = {1,2,3,4};
int f;

diria ao vinculador que precisava de 208 bytes para bss, 16 bytes para "dados" e 28 bytes para "const". Além disso, qualquer referência a uma variável seria substituída por um seletor de área e deslocamento, de modo que a, b, c, de ee seriam substituídos por dados bss + 0, const + 0, bss + 4, const + 24, dados +0 ou bss + 204, respectivamente.

Quando um programa é vinculado, todas as áreas bss de todos os módulos são concatenadas juntas; Da mesma forma, as áreas de dados e const. Para cada módulo, o endereço de qualquer variável relativa a bss será aumentado pelo tamanho das áreas de bss de todos os módulos anteriores (novamente, da mesma forma com dados e const). Assim, quando o vinculador estiver concluído, qualquer programa terá uma alocação de bss, uma alocação de dados e uma alocação const.

Quando um programa é carregado, geralmente ocorre uma das quatro coisas, dependendo da plataforma:

  1. O executável indicará quantos bytes ele precisa para cada tipo de dado e - para a área de dados inicializada, onde o conteúdo inicial pode ser encontrado. Também incluirá uma lista de todas as instruções que usam um endereço bss, dados ou constante. O sistema operacional ou o carregador alocará a quantidade apropriada de espaço para cada área e, em seguida, adicionará o endereço inicial dessa área a cada instrução que precisar.

  2. O sistema operacional alocará um pedaço de memória para armazenar todos os três tipos de dados e fornecerá ao aplicativo um ponteiro para esse pedaço de memória. Qualquer código que use dados estáticos ou globais desreferirá a referência desse ponteiro (em muitos casos, o ponteiro será armazenado em um registro durante o tempo de vida de um aplicativo).

  3. O sistema operacional inicialmente não alocará nenhuma memória para o aplicativo, exceto o que contém seu código binário, mas a primeira coisa que o aplicativo faz é solicitar uma alocação adequada do sistema operacional, que permanecerá para sempre em um registro.

  4. O sistema operacional inicialmente não alocará espaço para o aplicativo, mas o aplicativo solicitará uma alocação adequada na inicialização (como acima). O aplicativo incluirá uma lista de instruções com endereços que precisam ser atualizados para refletir onde a memória foi alocada (como no primeiro estilo), mas, em vez de ter o aplicativo corrigido pelo carregador do SO, o aplicativo incluirá código suficiente para se corrigir .

Todas as quatro abordagens têm vantagens e desvantagens. Em todos os casos, no entanto, o compilador consolidará um número arbitrário de variáveis ​​estáticas em um pequeno número fixo de solicitações de memória e o vinculador consolidará todas elas em um pequeno número de alocações consolidadas. Mesmo que um aplicativo precise receber um pedaço de memória do sistema operacional ou do carregador, é o compilador e o vinculador que são responsáveis ​​por alocar partes individuais desse pedaço grande a todas as variáveis ​​individuais que precisam dele.


13

O núcleo da sua pergunta é: "Como a memória é" alocada "em um arquivo compilado? A memória não é sempre alocada na RAM com todo o material de gerenciamento de memória virtual? A alocação de memória por definição não é um conceito de tempo de execução?"

Eu acho que o problema é que existem dois conceitos diferentes envolvidos na alocação de memória. Basicamente, a alocação de memória é o processo pelo qual dizemos "esse item de dados é armazenado nesse pedaço específico de memória". Em um sistema de computador moderno, isso envolve um processo de duas etapas:

  • Algum sistema é usado para decidir o endereço virtual no qual o item será armazenado
  • O endereço virtual é mapeado para um endereço físico

O último processo é puramente tempo de execução, mas o primeiro pode ser feito em tempo de compilação, se os dados tiverem um tamanho conhecido e um número fixo deles for necessário. Aqui está basicamente como funciona:

  • O compilador vê um arquivo de origem contendo uma linha que se parece com isso:

    int c;
  • Produz saída para o assembler que instrui a reservar memória para a variável 'c'. Isso pode ser assim:

    global _c
    section .bss
    _c: resb 4
    
  • Quando o montador é executado, ele mantém um contador que rastreia as compensações de cada item desde o início de um 'segmento' (ou 'seção') da memória. É como as partes de uma 'estrutura' muito grande que contém tudo no arquivo inteiro; não há memória real alocada para ele no momento e pode estar em qualquer lugar. Ele observa em uma tabela que _cpossui um deslocamento específico (por exemplo, 510 bytes desde o início do segmento) e depois incrementa seu contador em 4; portanto, a próxima variável será em (por exemplo) 514 bytes. Para qualquer código que precise do endereço de _c, basta colocar 510 no arquivo de saída e adicionar uma nota de que a saída precisa do endereço do segmento que contém a _cadição posteriormente.

  • O vinculador pega todos os arquivos de saída do assembler e os examina. Ele determina um endereço para cada segmento para que não se sobreponham e adiciona as compensações necessárias para que as instruções ainda se refiram aos itens de dados corretos. No caso de memória não inicializada como a ocupada porc(o montador foi informado de que a memória seria não inicializada pelo fato de o compilador colocá-la no segmento '.bss', que é um nome reservado para a memória não inicializada), inclui um campo de cabeçalho em sua saída que informa ao sistema operacional quanto precisa ser reservado. Pode ser realocado (e geralmente é), mas geralmente é projetado para ser carregado com mais eficiência em um endereço de memória específico, e o sistema operacional tentará carregá-lo nesse endereço. Nesse ponto, temos uma boa idéia de qual endereço virtual será usado c.

  • O endereço físico não será realmente determinado até que o programa esteja sendo executado. No entanto, do ponto de vista do programador, o endereço físico é realmente irrelevante - nunca descobriremos o que é, porque o sistema operacional geralmente não se incomoda em contar a ninguém, pode mudar com frequência (mesmo enquanto o programa está em execução) e um O principal objetivo do sistema operacional é abstrair isso de qualquer maneira.


9

Um executável descreve qual espaço alocar para variáveis ​​estáticas. Essa alocação é feita pelo sistema, quando você executa o executável. Portanto, sua variável estática de 1kB não aumentará o tamanho do executável com 1kB:

static char[1024];

A menos que você especifique um inicializador:

static char[1024] = { 1, 2, 3, 4, ... };

Portanto, além da 'linguagem de máquina' (ou seja, instruções da CPU), um executável contém uma descrição do layout de memória necessário.


5

A memória pode ser alocada de várias maneiras:

  • na pilha de aplicativos (a pilha inteira é alocada para seu aplicativo pelo SO quando o programa é iniciado)
  • na pilha do sistema operacional (para que você possa obter mais e mais)
  • na pilha controlada pelo coletor de lixo (o mesmo que os dois acima)
  • na pilha (para que você possa transbordar)
  • reservado no segmento de código / dados do seu binário (executável)
  • em local remoto (arquivo, rede - e você recebe um identificador, não um ponteiro para essa memória)

Agora sua pergunta é o que é "memória alocada em tempo de compilação". Definitivamente, é apenas um ditado incorretamente formulado, que deve se referir à alocação de segmento binário ou alocação de pilha, ou em alguns casos até a alocação de heap, mas nesse caso a alocação está oculta aos olhos do programador por chamada invisível do construtor. Ou provavelmente a pessoa que disse que apenas queria dizer que a memória não está alocada na pilha, mas não sabia sobre alocações de pilha ou segmento (ou não queria entrar nesse tipo de detalhe).

Mas na maioria dos casos, a pessoa só quer dizer que a quantidade de memória que está sendo alocada é conhecida no momento da compilação .

O tamanho binário será alterado apenas quando a memória estiver reservada no segmento de código ou dados do seu aplicativo.


1
Essa resposta é confusa (ou confusa), pois fala sobre "a pilha de aplicativos", "a pilha de SO" e "a pilha de GC" como se esses fossem conceitos significativos. Eu deduzo que, pelo número 1, você estava tentando dizer que algumas linguagens de programação (hipoteticamente) poderiam usar um esquema de "alocação de heap" que aloca memória de um buffer de tamanho fixo na seção .data, mas isso parece irrealista o suficiente para ser prejudicial para o entendimento do OP. Re # 2 e # 3, a presença de um GC realmente não muda nada. E re # 5, você omitiu a distinção relativamente MUITO mais importante entre .datae .bss.
Quuxplusone 26/01

4

Você está certo. A memória é realmente alocada (paginada) no momento do carregamento, ou seja, quando o arquivo executável é trazido para a memória (virtual). A memória também pode ser inicializada nesse momento. O compilador apenas cria um mapa de memória. [A propósito, os espaços de pilha e pilha também são alocados no tempo de carregamento!]


2

Eu acho que você precisa recuar um pouco. Memória alocada em tempo de compilação .... O que isso significa? Pode significar que a memória em chips que ainda não foram fabricados, para computadores que ainda não foram projetados, está de alguma forma sendo reservada? Não. Não, viagem no tempo, nenhum compilador que possa manipular o universo.

Portanto, isso significa que o compilador gera instruções para alocar essa memória de alguma forma no tempo de execução. Mas se você olhar do ângulo certo, o compilador gera todas as instruções, então qual pode ser a diferença. A diferença é que o compilador decide e, em tempo de execução, seu código não pode alterar ou modificar suas decisões. Se ele decidiu que precisava de 50 bytes em tempo de compilação, em tempo de execução, não é possível decidir alocar 60 - essa decisão já foi tomada.


Eu gosto de respostas que usam o método socrático, mas eu ainda te ofendi pela conclusão errônea de que "o compilador gera instruções para alocar a memória de alguma forma em tempo de execução". Confira a resposta mais votada para ver como um compilador pode "alocar memória" sem gerar nenhuma "instrução" de tempo de execução. (Observe que "instruções" em um contexto de linguagem assembly tem um significado específico, ou seja, códigos de execução executáveis. Você pode estar usando a palavra coloquialmente para significar algo como "receita", mas nesse contexto isso apenas confundirá o OP. )
Quuxplusone

1
@ Quuxplusone: eu li (e votei) essa resposta. E não, minha resposta não aborda especificamente a questão das variáveis ​​inicializadas. Também não trata de código auto-modificável. Embora essa resposta seja excelente, ela não abordou o que considero uma questão importante - colocar as coisas em contexto. Daí a minha resposta, que espero que ajude o OP (e outros) a parar e pensar no que está acontecendo ou pode estar acontecendo, quando eles têm problemas que não entendem.
jmoreno

@Quuxplusone: Desculpe se estou fazendo falsas alegações aqui, mas suponho que você também foi uma das pessoas que -1'ed a minha resposta. Em caso afirmativo, você se importaria de apontar terrivelmente qual parte da minha resposta foi a principal razão para fazê-lo e também gostaria de verificar minha edição? Eu sei que tenho pulado alguns pedaços sobre a verdadeira internos de como a memória de pilha é gerido, então eu adicionado agora um pouco sobre o meu não ser 100% exato para a minha resposta agora de qualquer maneira :)
Elias Van Ootegem

@jmoreno O argumento que você comentou sobre "Pode significar que a memória em chips que ainda não foram fabricados, para computadores que ainda não foram projetados, está de alguma forma sendo reservada? Não." é exatamente o falso significado que a palavra "alocação" implica, o que me confundiu desde o início. Eu gosto desta resposta porque se refere exatamente ao problema que eu estava tentando apontar. Nenhuma das respostas aqui realmente tocou esse ponto específico. Obrigado.
Talha disse

2

Se você aprender a programação de montagem, verá que é necessário esculpir segmentos para os dados, a pilha e o código, etc. O segmento de dados é onde vivem suas seqüências e números. O segmento de código é onde o seu código está localizado. Esses segmentos são incorporados ao programa executável. Claro que o tamanho da pilha também é importante ... você não iria querer um estouro de pilha !

Portanto, se seu segmento de dados tiver 500 bytes, seu programa terá uma área de 500 bytes. Se você alterar o segmento de dados para 1500 bytes, o tamanho do programa será 1000 bytes maior. Os dados são reunidos no programa real.

É o que está acontecendo quando você compila idiomas de nível superior. A área de dados real é alocada quando compilada em um programa executável, aumentando o tamanho do programa. O programa também pode solicitar memória em tempo real, e isso é memória dinâmica. Você pode solicitar memória da RAM e a CPU fornecerá para você usar, você poderá soltá-la e seu coletor de lixo a liberará de volta para a CPU. Pode até ser trocado para um disco rígido, se necessário, por um bom gerenciador de memória. Esses recursos são os idiomas de alto nível que você fornece.


2

Eu gostaria de explicar esses conceitos com a ajuda de alguns diagramas.

Isso é verdade que a memória não pode ser alocada em tempo de compilação, com certeza. Mas, o que acontece de fato no momento da compilação.

Aqui vem a explicação. Digamos, por exemplo, um programa tenha quatro variáveis ​​x, y, z e k. Agora, em tempo de compilação, ele simplesmente cria um mapa de memória, onde a localização dessas variáveis ​​entre si é determinada. Este diagrama irá ilustrá-lo melhor.

Agora imagine, nenhum programa está sendo executado na memória. Isso eu mostro por um grande retângulo vazio.

campo vazio

Em seguida, a primeira instância deste programa é executada. Você pode visualizá-lo da seguinte maneira. Este é o momento em que realmente a memória é alocada.

primeira instância

Quando a segunda instância deste programa estiver em execução, a memória terá a seguinte aparência.

segunda instância

E o terceiro ..

terceira instância

E assim por diante.

Espero que essa visualização explique bem esse conceito.


2
Se esses diagramas mostrassem a diferença entre memória estática e dinâmica, seriam IMHO mais úteis.
Bartek Banachewicz

Isso foi deliberadamente evitado por mim para manter as coisas simples. Meu foco é explicar essa funda com clareza, sem muita confusão técnica. Na medida em que isso se destina à variável estática .. Este ponto foi bem estabelecido por respostas anteriores. Então, pulei isso.
user3258051

1
Eh, esse conceito não é particularmente complicado, então não vejo por que torná-lo mais simples do que precisa, mas como ele é apenas uma resposta complementar, ok.
Bartek Banachewicz

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.