Por que devo usar malloc () quando “char bigchar [1U << 31-1];” funciona muito bem?

StackOverflow https://stackoverflow.com/questions/839291

  •  22-07-2019
  •  | 
  •  

Pergunta

Qual é a vantagem de usar malloc (além do retorno NULL em caso de falha) sobre matrizes estáticos? O programa a seguir vai comer toda a minha RAM e começar a preencher troca somente se os laços são comentada. Ele não falha.

...

#include <stdio.h>

unsigned int bigint[ 1u << 29 - 1 ];
unsigned char bigchar[ 1u << 31 - 1 ];

int main (int argc, char **argv) {
  int i;
/*   for (i = 0; i < 1u << 29 - 1; i++) bigint[i] = i; */
/*   for (i = 0; i < 1u << 31 - 1; i++) bigchar[i] = i & 0xFF; */

  getchar();
  return 0;
}

...

Depois de alguma tentativa e erro, eu encontrei o acima é o maior array estático permitido na minha máquina Intel de 32 bits com o GCC 4.3. É este um limite padrão, um limite do compilador, ou um limite máquina? Aparentemente eu posso ter como muitos deles como eu quero. Ele vai segfault, mas só se eu pedir (e tentar usar) mais de malloc me daria qualquer maneira.

Existe uma maneira de determinar se uma matriz estática foi realmente alocada e seguro de usar?

EDIT: Eu estou interessado no porquê malloc é usado para gerenciar o heap em vez de deixar a alça sistema de memória virtual lo. Aparentemente posso tamanho de uma matriz para muitas vezes o tamanho Acho que vou precisar eo sistema de memória virtual só irá manter-se em ram o que é necessário. Se eu nunca escrever a exemplo final (ou início) destes enormes matrizes, em seguida, o programa não usa a memória física. Além disso, se eu posso escrever para cada local, em seguida, o que faz malloc fazer além de incrementar um ponteiro na pilha ou pesquisar em torno atribuições anteriores no mesmo processo?

Nota do editor: 1 << 31 causas comportamento indefinido se int é de 32 bits, então eu ter modificado a questão de ler 1u. A intenção da questão é perguntar sobre a alocação de grandes buffers estáticos.

Foi útil?

Solução

Bem, por duas razões muito:

  1. Por causa da portabilidade, uma vez que alguns sistemas não vai fazer o gerenciamento de memória virtual para você.

  2. Você vai, inevitavelmente, precisam dividir essa matriz em pedaços menores para que seja útil, em seguida, para manter o controle de todos os pedaços, então, eventualmente, como você começar a "libertar" alguns dos pedaços da matriz que você não já exigem que você vai bater o problema da fragmentação de memória .

Ao todo, você vai acabar implementando uma série de funcionalidades de gerenciamento de memória (na verdade, praticamente reimplementar o malloc) sem o benefício da portabilidade.

Daí as razões:

  • portabilidade de código através de encapsulamento de gerenciamento de memória e padronização.

  • aumento da produtividade pessoal, pelo caminho da reutilização de código.

Outras dicas

com malloc você pode aumentar e diminuir sua matriz:. Torna-se dinâmica, para que possa alocar exatamente o que você precisa

Isso é chamado de gerenciamento de memória costume, eu acho. Você pode fazer isso, mas você vai ter de gerir esse pedaço de memória mesmo. Você ia acabar escrevendo seu próprio malloc () woring sobre este pedaço.

Em relação a:

Depois de alguma tentativa e erro eu encontrei o acima é a maior matriz estática permitido na minha máquina Intel de 32 bits com GCC 4.3. É este o padrão de um limite, um limite do compilador, ou uma máquina limite?

Um limite superior vai depender de como o de 4 GB (32-bit) de espaço de endereço virtual é dividida entre o espaço do usuário e espaço do kernel. Para Linux, acredito que o esquema mais comum particionamento tem um 3 Faixa GB de endereços para o espaço do usuário e uma gama de endereços para kernel-espaço de 1 GB. O particionamento é configurável pelo kernel do build-tempo, 2GB / 2GB e 1GB / 3GB splits também estão em uso. Quando o executável é carregado, espaço de endereço virtual deve ser alocada para cada objeto independentemente de memória real é alocado para apoiá-la.

Você pode ser capaz de alocar essa matriz gigantesca em um contexto, mas outros não. Por exemplo, se a matriz é um membro de um struct e você deseja passar a estrutura ao redor. Alguns ambientes têm um limite de 32K no tamanho do struct.

Como mencionado anteriormente, você também pode redimensionar a memória para usar exatamente o que você precisa. É importante em contextos de desempenho-críticos a não ser a paginação para a memória virtual se ele pode ser evitado.

Não há nenhuma maneira de alocação de pilha livre que não vai fora do escopo. Então, quando você realmente usar alocação global e VM tem que alloc você memória real duro, ele é alocado e vai ficar lá até que seu programa se esgote. Isto significa que qualquer processo só vai crescer nele do uso de memória virtual (funções têm alocações de pilha locais e estes serão "libertados").

Você não pode "manter" a memória de pilha, uma vez que sai do escopo da função, é sempre liberado. Portanto, você deve saber quanta memória você vai usar em tempo de compilação.

O que então se resume a quantas int foo [1 << 29] é que você pode ter. Desde primeiro ocupa memória inteira (em 32 bits) e será (permite mentira: 0x000000) o segundo irá resolver para 0xffffffff ou thereaobout. Em seguida, o terceiro iria resolver a quê? Algo que os ponteiros de 32 bits não podem expressar. (Lembre-se que as reservas de pilha são resolvidas parcialmente em compiletime, parcialmente tempo de execução, através de compensações, o quão longe a pilha de deslocamento é empurrado quando você alloc esta ou aquela variável).

Portanto, a resposta é muito bonito que uma vez que você tem int foo [1 << 29] você não pode ter qualquer profundidade razoável de funções com outras variáveis ??de pilha locais mais.

Você realmente deve evitar fazer isso se você não sabe o que está fazendo. Tente único pedido o máximo de memória que você precisa. Mesmo se ele não está sendo usado ou ficar no caminho de outros programas que podem atrapalhar o processo de sua auto. Há duas razões para isso. Em primeiro lugar, em determinados sistemas, particularmente de 32 bits queridos pode causar espaço de endereço a ser esgotados prematuramente em circunstâncias raras. Além disso muitos kernels ter algum tipo de per processo de limite no reservada / / virtual não na memória uso. Se o seu programa pede memória em pontos no tempo de execução do kernel pode matar o processo, se ele pede para a memória a ser reservado que excede este limite. Já vi programas que quer ter deixado de funcionar ou saído devido a uma malloc falhou porque eles estão reservando GBs de memória enquanto usando apenas alguns MB.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top