Por que malloc alocar um número diferente de bytes do que o solicitado?
Pergunta
Eu tenho este pedaço de código
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
int main(){
void *a, *b;
a = malloc(16);
b = malloc(16);
printf("\n block size (for a): %p-%p : %li", b, a, b-a);
a = malloc(1024);
b = malloc(1024);
printf("\n block size (for a): %p-%p : %li", b, a, b-a);
}
isto não deveria imprimir o último tamanho do bloco alocado (16 ou 1024)? -Lo em vez imprime 24 e 1032, assim que a quantidade de memória alocada parece ter 8 bytes extras.
O meu problema é (antes de fazer este caso de teste) que eu faço malloc()
em uma função (1024 bytes), e retornar o resultado alocado. Ao verificar o tamanho do bloco sobre a função retornar Recebo 516 blocos ... e eu não entendo por que. Eu acho que essa pode ser a razão para a corrupção da memória que ocorre depois de fazer algum processamento sobre os buffers alocados:)
Editar: Eu vi Como posso obter o tamanho de uma matriz de um ponteiro em C? e parece perguntar a mesma coisa, pena de repostagem.
Eu tenho refeito meu exemplo para o meu código mais específico:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
short int * mallocStuff(long int number, short int base){
short int *array;
int size=1024;
array=(short int*)calloc(1,size);
//array=(short int*)malloc(size);
return array;
}
int main(){
short int **translatedArray;
translatedArray=malloc(4*sizeof(short int));
int i;
for(i=0;i<4;i++){
translatedArray[i]=mallocStuff(0,0);
if(i>0)
printf("\n block size (for a): %p-%p : %i",
translatedArray[i], translatedArray[i-1], translatedArray[i]-translatedArray[i-1]);
}
return 0;
}
E a saída é
block size (for a): 0x804a420-0x804a018 : 516
block size (for a): 0x804a828-0x804a420 : 516
block size (for a): 0x804ac30-0x804a828 : 516
De acordo com o post acima que é maior do que 1024. Estou errado?
Solução
Você tem um bug. Em vez de:
translatedArray=malloc(4*sizeof(short int));
Você deve ter
translatedArray=malloc(4*sizeof(short int*));
Observe o ponteiro faltando em seu código. Eu suspeito que este é o lugar onde o seu comportamento observado deriva.
Note também que 0x804a420 - 0x804a018 = 1032
, não 516
. A fórmula translatedArray[i] - translatedArray[i - 1]
dá-lhe o número de elementos (ints curtas, ou mais simplesmente, calções) entre os dois endereços, e não o número de bytes .
Outras dicas
Em primeiro lugar, Malloc não garante que duas chamadas malloc sucessivas retornam ponteiros sucessivas.
Em segundo lugar, dependendo de sua arquitetura específica, regras de alinhamento diferentes se aplicam; às vezes você pode pedir para um único byte, mas a arquitetura prefere alocações em intervalos de 8 ou 4 bytes.
Em terceiro lugar, malloc precisa de alguma sobrecarga para armazenar o tamanho do bloco alocado é, etc.
Não faça suposições sobre o que malloc está fazendo além do que diz a documentação!
A função malloc
sempre aloca um pouco mais do que você pedir, a fim de armazenar algumas informações de contabilidade. Afinal, quando você chamar free()
ele precisa saber quão grande é o bloco é.
Além disso, geralmente implementações malloc
irá arredondar o tamanho solicitado para o próximo múltiplo de 8, 16 ou algum outro número ish-round.
Atualizar : A verdadeira resposta para a sua pergunta está na sua utilização do tipo short int
. Ao fazer aritmética de ponteiro (subtração) entre ponteiros digitadas, C e C ++ voltar a diferença no número de coisas apontado. Desde que você está apontando para short int
, que é de dois bytes de tamanho, o valor devolvido é a metade do que você está esperando.
Por outro lado, malloc
sempre aloca um determinado número de bytes , não importa o que você converter o resultado para depois. Tente isto:
array=(short int*)malloc(sizeof(short int) * size);
Não há garantias de que duas chamadas malloc retornar blocos exatamente embalados juntos - na verdade, não existem quaisquer garantias sobre o resultado em tudo, exceto que se é não NULL ele vai apontar para um bloco de pelo menos tão grande quanto a um solicitado.
Internamente, a maioria dos mallocs armazenar dados trabalhando para ajudá-los a gerenciar o heap. Por exemplo, esses 8 bytes pode conter dois ponteiros - um apontando para o próximo bloco, e um apontando para o bloco anterior. Eu não sei o que esses 8 bytes são, porque você não mencionou que OS você está rodando, mas é perfeitamente normal para malloc usar alguma memória para si nos bastidores.
Alguns alocadores (por exemplo, no Windows) fornecem uma função de biblioteca para descobrir o tamanho do bloco dado um ponteiro, no entanto, outros não, como é um recurso bastante esotérico.
O que retorna malloc depende da implementação de malloc, ea arquitetura. Como outros já disseram, você está garantido para obter pelo menos a quantidade de memória solicitada ou NULL. É também por isso, às vezes, você pode escrever passado o fim de uma matriz, e não obter uma falha de segmentação. É porque você realmente têm acesso válido para esta memória, você simplesmente não sabe disso.
malloc () é normalmente implementado pela divisão da pilha disponível em pedaços de vários tamanhos. No seu caso, malloc () retorna 2 consecutivos 1024 (ou 16) de pedaços de byte. O espaço de 8 bytes que você menciona é usado por malloc () para obter informações de contabilidade.
malloc See de Doug Lea () notas Impl aqui para entender o que está acontecendo por trás das cenas: http://g.oswego.edu/dl/html/malloc.html
malloc()
terá a sua própria sobrecarga.
Para não mencionar que não há nenhuma garantia de que 2 alocações consecutivos estará ao lado do outro, para começar.
Se malloc
retornos outra coisa senão nulo, então a memória que foi alocada para o seu programa tem o tamanho que você passou para malloc
. Tomando a diferença ponteiro entre os valores de retorno de duas chamadas diferença para malloc
poderia ter qualquer valor e não tem nada (bem pouco) a ver com o tamanho do bloco do primeiro bloco alocado.
Eu encontrei this..and seleção para o link abaixo para mais informações.
Alocação
Um bloco é atribuído a partir da piscina livre por primeiro converter os bytes solicitados para um índice no conjunto de balde, com a seguinte equação:
necessário = requerido + 8
Se necessário <= 16, então balde = 0
Se necessário> 16, então balde = (log (necessário) / log (2) arredondado para baixo, para o inteiro mais próximo) - 3
O tamanho de cada bloco na lista ancorado pelo balde é o tamanho do bloco = 2 balde + 4. Se a lista no balde é nulo, a memória é alocada usando a sub-rotina sbrk para adicionar blocos para a lista. Se o tamanho do bloco é menor do que uma página, em seguida, uma página é alocada usando a sub-rotina sbrk, e o número de blocos igual ao quociente o tamanho do bloco para o tamanho da página são adicionados à lista. Se o tamanho do bloco é igual ou maior do que uma página, memória necessária é alocada usando a sub-rotina sbrk, e um único bloco é adicionado à lista livre para o balde. Se a lista livre não é vazio, o bloco no topo da lista é retornada para o chamador. O próximo bloco na lista, em seguida, torna-se o novo chefe.
Antes do ponteiro está o tamanho da seguinte matriz, que é um 32/64 bit inteiro (não sei se assinado ou não assinado)
assim que a quantidade de memória alocada parece ter 8 bytes extras? implementação malloc()
em seu sistema parece alocar bytes extras para manter as informações de meta-dados como como seção grande pilha é, o que está começando endereço Info etc.
Apesar de seus varia em diferentes plataformas.
Em meus sistemas x86, malloc()
alocar min de bytes 17
, mesmo que eu estou solicitando malloc(0)
.
int main(void) {
int *p = malloc(0);
if(p == NULL) {
/* error handling */
}
printf("%d\n",p[-1]);/ *it prints 17 bytes */
/* some code */
return 0;
}
malloc () pode alocar memória contígua, mas quando o seu malloc telefone () 2 vezes e não pode esperar memória alocada para ser contíguo subtraindo dois ponteiros variabls ...
No entanto memória alocada é a memória virtual que faz parte da implementação do kernel, gerenciamento de memória (VFS) para ser específico. Pode não afetar a funcionalidade do aplicativo.