OutOfMemoryException durante o preenchimento do MemoryStream: alocação de 256 MB no sistema de 16 GB

Estou executando o seguinte método no meu servidor IIS de desenvolvimento (do VS2010 IDE) em uma máquina Windows 7 de 64 bits com 16 GB de RAM instalada:

public static MemoryStream copyStreamIntoMemoryStream(Stream stream) { long uiLen = stream.Length; byte[] buff = new byte[0x8000]; int nSz; MemoryStream ms = new MemoryStream(); try { while ((nSz = stream.Read(buff, 0, buff.Length)) != 0) { ms.Write(buff, 0, nSz); } } finally { Debug.WriteLine("Alloc size=" + ms.Length); } return ms; } 

e recebo o System.OutOfMemoryException nesta linha:

 ms.Write(buff, 0, nSz); 

Isso é lançado quando 268435456 bytes são alocados:

Tamanho do alocamento = 268435456

que é 0x10000000 ou 256 MB. Então, eu estou querendo saber se há alguma configuração global que eu preciso definir para fazer o trabalho?

Aqui está uma captura de canvas da configuração do projeto: insira a descrição da imagem aqui

Resposta curta – servidor dev é um processo de 32 bits.

Resposta longa para “por que apenas 256MB?”

Primeiro de tudo, vamos entender como funciona.

O MemoryStream tem um buffer interno de byte [] para manter todos os dados. Ele não pode prever o tamanho exato desse buffer, então ele apenas o inicializa com algum valor inicial.

As propriedades Position e Length não refletem o tamanho real do buffer – elas são valores lógicos para refletir quantos bytes são gravados e podem ser facilmente menores do que o tamanho real do buffer físico.

Quando este buffer interno não pode caber todos os dados, ele deve ser “redimensionado”, mas na vida real isso significa criar um novo buffer duas vezes maior que o anterior e depois copiar os dados do buffer antigo para o novo buffer.

Então, se o tamanho do seu buffer é 256Mb, e você precisa que novos dados sejam gravados, isso significa que o .Net precisa encontrar outro bloco de dados de 512Mb – tendo todo o resto no lugar, então o heap deve ter pelo menos 768Mb o momento da alocação de memory quando você recebe OutOfMemory.

Observe também que, por padrão, nenhum object único, incluindo matrizes, no .Net pode ter mais de 2 Gb de tamanho.

Ok, então aqui está a amostra que simula o que está acontecendo:

  byte[] buf = new byte[32768 - 10]; for (; ; ) { long newSize = (long)buf.Length * 2; Console.WriteLine(newSize); if (newSize > int.MaxValue) { Console.WriteLine("Now we reach the max 2Gb per single object, stopping"); break; } var newbuf = new byte[newSize]; Array.Copy(buf, newbuf, buf.Length); buf = newbuf; } 

Se ele é construído em x64 / AnyCPU e é executado a partir do console – tudo está ok.

Se ele for construído em x86, ele falhará no console.

Se você colocá-lo para dizer Page_Load, construído em x64 e abrir a partir do servidor web VS.Net – ele falhará.

Se você fizer o mesmo com o IIS – está tudo bem.

Espero que isto ajude.

Se você estiver usando o servidor de desenvolvimento VS padrão, estará executando o código no processo x86 / 32 bit. Se você estiver usando o IIS completo – muito provavelmente no IIS, o AppPool é configurado para ser executado no x86 (modo de 32 bits) e como resultado ter espaço de endereço muito limitado (2 GB, a menos que você tenha marcado seu aplicativo como Large Address Aware).

No caso do IIS, certifique-se de configurar as pesquisas de aplicativos para executar x64 (não tenho certeza do que é padrão). Certifique-se de que seu código seja target está definido como AnyCPU ou x64.

Para aplicativos C # independentes – por padrão, eles são compilados com plataforma de destino x86 ou AnyCPU / Prefer x86 – para x64.

Para obter suporte a x64 para o IIS, você pode instalar o IIS completo ou instalar o IIS Express 8.0 (o 7.5 fornecido com o Windows 7 é somente de 32 bits) em Download IIS 8.0 Express .

Notas laterais:

  • Se você acabou de instalar o IIS completo, certifique-se de atualizar sua solução para usar o IIS para o host do site.
  • Não tenho máquina para verificar se alguma etapa adicional precisa usar o suporte a x64 para o IIS Express. Confira esta pergunta – Não é possível obter o IIS Express 8 beta para executar o site como um processo de 64 bits – pois ele pode fornecer algumas ideias.
  • Você também pode tentar criar sua própria versão x64 do servidor de desenvolvimento com base nas sugestões aqui – O WebDev WebSev (Cassini) do Visual Studio 2010 é compatível com 64 bits?