Frage .Net Bitmap Klassenkonstruktor (int, int) und (int, int, PixelFormat) wirft ArgumentException auf vollkommen gute Argumente


Ich habe einen Code, der so etwas macht (Irrelevante Bits abgeschnitten):

void foo(Bitmap bmp1, Bitmap bmp2)
{
    Bitmap bmp3;
    if(something)
        bmp3 = new Bitmap(bmp1.Width, bmp1.Height + bmp2.Height);
    else
        bmp3 = new Bitmap(bmp1.Width, 18000);
    (more stuff here that runs fine)
}

Irgendwann lief das meistens gut. Zu Beginn. Als das Projekt fortfuhr, begann es auf der neuen Bitmap-Linie zu scheitern. Der Fehler gibt es: "ArgumentException wurde nicht behandelt. Parameter ist nicht gültig." Es wird nicht erwähnt, mit welchem ​​Parameter es ein Problem hat oder irgendetwas. Ich bin ratlos. Hier ist, was ich sicher weiß:

  1. bmp1 und bmp2 waren niemals null wenn dieser Fehler ausgelöst wird.
  2. Die Anwesenheit der if-Anweisung hat hat nie einen Unterschied gemacht; es stirbt genauso oft ohne.
  3. Beide Beispiele des Konstruktors verwenden habe diesen Fehler geworfen.

Ich bin versucht zu sagen, dass dies ein Speicherfehler ist, außer dass nichts dergleichen erwähnt wird. Das erste Dutzend Mal oder so geschah es, dass die Höhen mehr als 18000 betrugen (daher die magische Zahl oben). Als wir feststellten, dass es eine Art weiche Barriere für unser System war, beschränkten wir die Bilder auf diese Höhe, wodurch die Ausnahmen nach einiger Zeit verschwanden.

Für einige Beispieldaten hat die Ausnahme, die ich gerade anschaue, bmp1.Width bei 2550, bmp1.Height bei 6135 und bmp2.Height bei 6285.

Hat jemand Ideen?


8
2017-12-22 20:47


Ursprung


Antworten:


GDI + generiert keine sehr guten Ausnahmebedingungsnachrichten. Die Ausnahme, die Sie haben, ist flockig, diese wird es zuverlässig auf meinem Rechner erzeugen:

    private void button1_Click(object sender, EventArgs e) {
        var bmp = new Bitmap(20000, 20000);
    }

Was wirklich vor sich geht, ist, dass diese Bitmap zu viel zusammenhängend nicht verwalteten Speicher benötigt, um die Bitmap-Bits zu speichern, mehr als in Ihrem Prozess verfügbar ist. Auf einem 32-Bit-Betriebssystem können Sie nur hoffen, einen Speicherbereich um 550 Megabyte zuzuweisen. Das geht von dort aus schnell bergab.

Das Problem ist Adressraumfragmentierung, der virtuelle Speicher Ihres Programms speichert eine Mischung aus Code und Daten an verschiedenen Adressen. Der gesamte Speicherplatz ist ungefähr 2 Gigabyte, aber das größte Loch ist viel kleiner. Sie können nur den gesamten Speicher mit vielen kleinen Zuweisungen verbrauchen, große versagen viel schneller.

Kurz gesagt: Es versucht Ihnen zu sagen, dass die angeforderte Größe nicht unterstützt werden kann.

Ein 64-Bit-Betriebssystem hat dieses Problem nicht. Stellen Sie sicher, dass Sie dies mit der Registerkarte "Projekt"> "Eigenschaften"> "Erstellen", "Plattformziel = AnyCPU" und "Bevorzugt 32-Bit = nicht aktiviert" nutzen. Außerdem setzt WPF auf WIC, eine Imaging-Bibliothek, die viel intelligenter ist, wenn es um die Zuordnung von Puffern für Bitmaps geht.


19
2017-12-22 21:19



Überprüfen Sie, ob bmp1 oder bmp2 disponiert wurde (auch wenn nicht null). Siehe hier:

Der mysteriöse Parameter ist keine gültige Ausnahme


1
2017-12-22 21:14



Hat jemand Ideen?

Wickeln Sie den Anruf, der wirft ArgumentException mit einem try-catch(Exception ex) und gehen Sie in den Ausnahmeblock, um die rohe Ausnahme zu sehen. Es sollte geben Sie mehr Details, wie das Argument angeblich ungültig ist.

try
{
    bmp3 = new Bitmap(bmp1.Width, bmp1.Height + bmp2.Height);
}
catch (Exception ex)
{   
    throw;  // breakpoint here, examine "ex"
}

0
2017-12-22 20:51