web-dev-qa-db-fra.com

OutOfMemoryException lors du remplissage de MemoryStream: allocation de 256 Mo sur un système de 16 Go

J'exécute la méthode suivante sur mon développement IIS (à partir de VS2010 IDE) sur une machine Windows 7 64 bits avec 16 Go de RAM installée:

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;
}

et je reçois le System.OutOfMemoryException sur cette ligne:

ms.Write(buff, 0, nSz);

Cela est levé lorsque 268435456 octets sont alloués:

Taille d'allocation = 268435456

qui est 0x10000000 ou 256 Mo. Je me demande donc s'il y a un paramètre global que je dois définir pour le faire fonctionner?

Voici une capture d'écran du paramètre de configuration du projet: enter image description here

18
c00000fd

Réponse courte - le serveur de développement est un processus 32 bits.

Réponse longue pour "pourquoi seulement 256 Mo?"

Tout d'abord, comprenons comment cela fonctionne.

MemoryStream possède un tampon d'octets [] interne pour conserver toutes les données. Il ne peut pas prédire la taille exacte de ce tampon, il l'initialise donc simplement avec une valeur initiale.

Les propriétés de position et de longueur ne reflètent pas la taille réelle du tampon - ce sont des valeurs logiques qui reflètent le nombre d'octets écrits et peuvent facilement être plus petites que la taille réelle du tampon physique.

Lorsque ce tampon interne ne peut pas contenir toutes les données, il doit être "redimensionné", mais dans la vraie vie, cela signifie création d'un nouveau tampon deux fois plus grand que le précédent, puis copie des données de l'ancien tampon vers un nouveau tampon.

Donc, si la longueur de votre tampon est de 256 Mo et que vous avez besoin de nouvelles données à écrire, cela signifie que .Net doit trouver un autre bloc de données de 512 Mo - ayant tout le reste en place, donc le tas doit être d'au moins 768 Mo sur le moment de l'allocation de mémoire lorsque vous recevez OutOfMemory.

Veuillez également noter que par défaut, aucun objet, y compris les tableaux, dans .Net ne peut prendre plus de 2 Go.

Ok, voici donc l'exemple d'échantillon qui simule ce qui se passe:

        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;
        }

S'il est intégré à x64/AnyCPU et fonctionne à partir de la console - tout va bien.

S'il est construit sur x86 - il échoue dans la console.

Si vous dites qu'il s'agit de▶Load, construit en x64 et ouvert à partir du serveur Web VS.Net - il échoue.

Si vous faites de même avec IIS - tout va bien.

J'espère que cela t'aides.

27
Lanorkin

Si vous utilisez le serveur de développement VS par défaut, vous exécutez du code dans un processus x86/32 bits. Si vous utilisez IIS - très probablement dans IIS AppPool particulier est configuré pour s'exécuter en x86 (mode 32 bits) et que, par conséquent, l'espace d'adressage est très limité) (2 Go, sauf si vous avez marqué votre application comme étant compatible avec les grandes adresses).

Dans le cas de IIS assurez-vous que vous avez configuré les sondages d'application pour exécuter x64 (pas sûr de ce qui est par défaut). Assurez-vous que votre code cible est défini sur AnyCPU ou x64.

Pour les applications C # autonomes - par défaut, elles sont compilées avec x86 ou AnyCPU/Prefer x86 - changez la plate-forme cible en x64.

Pour obtenir la prise en charge x64 de IIS vous pouvez soit installer IIS complet ou installer IIS Express 8.0 (7.5 fourni avec Windows 7 est 32 bits uniquement) depuis Télécharger IIS 8.0 Express .

Notes annexes:

6
Alexei Levenkov