Laden...

Größeres Array verwenden als der INT-Laufindex zuläßt

Erstellt von digi333 vor 10 Jahren Letzter Beitrag vor 10 Jahren 1.793 Views
D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 10 Jahren
Größeres Array verwenden als der INT-Laufindex zuläßt

Ich brauche ein Float-Array von mehr als 2^31 Zellen, aber wie?


int cells = Rows*Columns; // 17001*216411=3679203411
float[] f = new float[cells];

Man sieht schnell, dass cells größer ist als der Wertebereich von Integer.

C
2.121 Beiträge seit 2010
vor 10 Jahren

Du weißt dass du dazu über 14 GB freien Speicher brauchst? Vielleicht hat sich deine Idee ja schon mit dieser Überlegung erledigt 😃

Falls nicht, könntest du mit einer eigenen Klasse nachhelfen, die einen long Index bekommt und damit eine interne Struktur ausliest. Dir würden zwei Arrays mit int Index genügen, die anhand des höchsten Bits in deiner Zahl unterschieden werden.

Was machst du denn dass du da wirklich so umfangreiche Daten hast?

Edit: Was mir auch noch einfällt, sind wirklich alle Zellen des Array gefüllt oder nur sehr wenige? In letzterem Fall könntest du evtl. auch ein Dictionary verwenden.

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 10 Jahren

Ich hab 32 GB und noch eine 512 GB SSD Festplatte zum auslagern. Sollte reichen. Wie sieht eine eigene Array-Klasse aus mit einem long als Index-Variable?

6.911 Beiträge seit 2009
vor 10 Jahren

Hallo digi333,

wenn du .net 4.5 benützt, so kannst du das 2GB-Limit für ein Objekt außer Kraft setzen indem <gcAllowVeryLargeObjects> auf true gesetzt wird.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo digi333,

es wäre sicher nicht so aufwändig, eine eigene Array-/List-Klasse zu schreiben, die intern ein Array von Arrays benutzt, welche alle kleiner als 2GB sind. Man muss den Index dann nur (mit Bitoperationen) aufteilen, um anschließend mit zwei Indexzugriffen an den gewünschten Wert zu kommen. Das hätte den Vorteil, dass der Speicher nicht in einem zusammenhängenden Stück benötigt wird, sondern es reicht, wenn die freien Speicherbereiche groß genug für die Teil-Arrays sind.

herbivore

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 10 Jahren

Ich hab das Projekt in VS2012 mit x64 und in der "App.config" folgendes eingetragen.


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" />
  </runtime>
</configuration>

Im Hauptprogramm steht nicht mehr als...


long t = 3679203411;
float[] a = new float[t];

Dennoch kommt eine > Fehlermeldung:

OverflowException nicht behandelt

S
417 Beiträge seit 2008
vor 10 Jahren

Du solltest auch den Kommentar auf der MSDN Seite berücksichtigen:

Zitat von: Element
The maximum number of elements in an array is UInt32.MaxValue.

O
79 Beiträge seit 2011
vor 10 Jahren

Würde ein zweidimensionales Array nicht auch gehen ?

float a[][] = new float[Rows][Cols];

oder so ähnlich 😉

F
10.010 Beiträge seit 2004
vor 10 Jahren

Ich brauche ein Float-Array von mehr als 2^31 Zellen, aber wie?

Warum?

In 105% aller Fälle kommt so eine Anforderung weil sich jemand nicht vorher mit Datendesign oder den Anforderungen auseinandersetzt.

Warum meinst du also ein zusammenhängendes Array von mehr als 16GB haben zu müssen?

742 Beiträge seit 2005
vor 10 Jahren

Im übrigen kann ich mir auch gut vorstellen, dass es aufgrund der Fragementierung des Speichers gar nicht möglich ist, ein so großes Array am Stück zu allokieren.

Mal dahingestellt, dass du es wirklich brauchst, würde ich dir schon dafür zu vielen kleinen Arrays raten. Also 10MB Blöcke oder so. Wenn du das geschickt machst, kannst du auch was schreiben, um das auf die Platte zu bringen und mit weniger Speicher auskommen.

sowas wie:



byte[] Get(long position)
{
    long pageNumber = position / pageSize;

    var page = lruCache[pageNumber ];
    if (page == null)
    {
        page = ReadFromFS(pageNumber );
    
        var replaced = lruCache.Set(pageNumber, page);
        
        if (replaced != null && replaced.PageNumber != pageNumber && replaced.HasChanged)
        {
             WriteToFS(replaced);
        }
    }

    return page.Get(position - page * pageNumber );
}