Programação imperativa
9. Memória
Utilização da memória pelos
programas.
Memória estática e memória
automática.
9. Memória
Utilização da memória pelos
programas.
Memória estática e memória
automática.
As variáveis residem na memória
Cada variável que usamos residirá na memória do computador quando o programa for executado.
A memória é uma parte do hardware do computador. É
formada por uma sequência de células de memória,
chamadas bytes.
Cada byte é formado por 8 bits.
Um bit é um dispositivo eletrónico que em cada momento estará num de dois estados.
Cada byte é referenciado pelo seu endereço, que é um número inteiro.
O endereço de uma variável é o endereço da primeira célula de memória ocupada por essa variável.
Semântica abstrata
Qual é o significado da seguinte instrução?
O significado é: depois da execução da
instrução, o valor x é igual à soma do valor de
y com o valor de z.
Está implícito que y e z ficam na mesma.
Note que o significado é explicado sem
nenhuma referência ao computador.
5
Semântica concreta
Qual é o significado da seguinte instrução?
O significado é:
O conteúdo da posição de memória identificada pela variável y é copiado para um registo.
O conteúdo da posição de memória identificada pela variável z é copiado para um outro registo.
A unidade aritmética realiza o cálculo da soma do valor
numérico presente no primeiro registo com valor numérico presente no segundo registo, deixando o resultado no
primeiro registo.
O conteúdo do primeiro registo é copiado para a posição de memória identificada pela variável x.
Afetação de elementos de arrays
Sendo a um array de int e x uma variável int, qual é o
significado da seguinte instrução?
O significado é: depois do depois da execução da
instrução, o valor x é igual ao valor do i-ésimo
elemento do array.
Ou então:
Seja p o endereço do primeiro elemento do array e q o endereço da variável x.
O conteúdo dos bytes nos endereços p+4*i, p+4*i+1,
p+4*i+2 e p+4*i+3 são copiados os bytes de endereço q, q+1, q+2 e q+3, respetivamente.
7
x = a[i];
Estamos a admitir que as variáveis de tipo int ocupam quatro bytes.
Observando a memória
O ambiente de desenvolvimento permite-nos observar a memória. Eis o programa que vamos observar: int primes[10] = {2,3,5,7,11,13,17,19,23,29}; int powers[12] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048}; void t1(void) { int a[4]; int i; for (i = 0; i < 4; i++) a[i] = 2 * primes[i]; } int main(void) { t1(); return 0; }
Janelas sobre a memória
9
Janela autos: podemos observar que o endereço do array primes é 01117060, o do array powers é 01117088 e o do array a é
001efd40 e que o valor de i é 3.
Estado da variável a, quando i vale 3, imediatamente a seguir à afetação.
Zona da variável i.
9. Memória
Utilização da memória pelos
programas.
Memória estática e memória
automática.
Gestão da memória
Quando o sistema operativo lança a execução de um
programa, atribui ao programa um espaço de
memória, para uso exclusivo do programa.
Todas as variáveis do programa residirão nesse
espaço de memória.
Nem todas as variáveis usadas pelo programa
estarão residentes na memória durante toda a
execução do programa.
A gestão do espaço da memória é realizada pelo
programa em colaboração com o sistema operativo.
Memória estática
As variáveis externas, isto é, as variáveis declaradas fora das funções, ficam na memória estática e existem desde que o programa arranca até que o programa termina. Note bem: a memória estática não é um conceito de hardware; é apenas a zona da memória atribuída ao programa onde ficam as variáveis externas.
Tipicamente, as variáveis externas contêm valores de referência, que não mudam, usados em todo o
programa.
As variáveis externas são globais, isto é, podem ser acedidas a partir de qualquer função.
Memória automática
As variáveis locais, isto é, as variáveis declaradas dentro das funções, incluindo os argumentos da função, só
existem na memória quando as funções estão ativas.
Quando uma função f2 é chamada por uma função f1, o
espaço de memória necessário para todas as variáveis da função f1 é alocado automaticamente na pilha de
execução, a seguir ao espaço de memória que terá sido
alocado anteriormente para a função f1.
Quando uma função f2, chamada por uma função f1,
retorna, o espaço de memória reservado para f2 na pilha de execução é libertado e todas as variáveis de f2, na
presente ativação da função, deixam de existir em memória.
Observando a memória automática
Já vimos, no exemplo da função t1, que as
variáveis externas ficam numa zona da
memória distante da zona das variáveis locais:
Variáveis locais, memória estática
Variáveis externas,
memória estática
Tínhamos observado que a variável i estava no
Exemplo com dois arrays
Consideremos a função h1 e a função de teste t2:
15
int h1(int *a, int n) { int numbers[20]; int squares[20]; int i; for (i = 0; i < n; i++) numbers[i] = a[i]; for (i = 0; i < n; i++)
squares[i] = numbers[i] * numbers[i]; return n; } void t2(void) { int x; x = h1(primes, 6); printf("%d\n", x); }
Note bem: esta função não calcula nada de interessante. Serve
apenas para nós
Dois arrays
Caso dos subarrays
Consideremos a função de teste t3:
17
int h1(int *a, int n) { int numbers[20]; int squares[20]; int i; for (i = 0; i < n; i++) numbers[i] = a[i]; for (i = 0; i < n; i++)
squares[i] = numbers[i] * numbers[i]; return n; } void t3(void) { int x; x = h1(primes, 6); printf("%d\n", x); }
Note bem: esta função não calcula nada de interessante. Serve
apenas para nós
Subarrays
Exemplo com duas funções
Observemos uma
função de teste t4,
que chama uma
função h3, a qual
chama uma função
h2. Tanto h3 como h2
declaram um array
local.
19
int h2(int *a, int n) {
int squares[8]; int i;
for (i = 0; i < n; i++) squares[i] = a[i] * a[i]; return n;
}
int h3(int *a, int n) { int pred[8]; int i; for (i = 0; i < n; i++) pred[i] = a[i] - 1; h2(pred, n); return n; } void t4(void) { int x; x = h3(primes, 6); printf("%d\n", x); }
Duas funções
Variáveis externas:Variáveis locais da função h3: