Kjapp og trygg hosting for Wordpress

VB.NET - Kan man unngå "System.OutOfMemory" med mer RAM?

Stian O

Medlem
Hei,

Jeg benytter VB.NET til å utføre Monte Carlo-simuleringer (finans). Jeg vet ikke hvor godt du kjenner til dette, men i bunn og grunn er dette en måte å gjøre MANGE eksperimenter der vanlige statistiske / matematiske metoder ikke strekker til.

Uheldigvis sliter jeg med feilmeldingen:

"Exception of type 'System.OutOfMemoryException' was thrown."

Skyldes dette kun at maskinene har gått tom for RAM eller er det annet som ligger bak?
Tenker f.eks. på 32bit vs 64bit begrensinger...?

Holder det at jeg kjøper et (64 bit) system med masse RAM så er problemet løst?

Nedenfor er en enkel kode (med en uendelig loop) for å illustrere problemet.
Private Sub testMemory()
Dim RandomClass As New Random()
Dim upper As Integer = 1000000
Dim random(upper) As Integer
Dim i As Integer = 0
Do
If i > upper Then
upper += 1000000
ReDim Preserve random(upper)
End If
random(i) = RandomClass.Next
i += 1
Loop
End Sub


Denne vil selvsagt krasje før eller siden, men den gjør det allerede når upper = 102,000,000. Skulle gjerne sett at det først skjedde rundt en millard...
 
Sist redigert:

Stian O

Medlem
"Skulle tro at OSen ikke bare tillater din webserver"

Sorry, glemte å nevne at jeg kjører koden på min laptop; 64bit Windows Vista
 

adeneo

Medlem
Jeg er skrekkelig dårlig på VB, men prøver meg med min begrensede kunnskap om både Monte Carlo metoder og VB.

Det ser ut som du har noe som kalles for en factorial (if statement) og en loop som går evig, og som du sier så vil dette til slutt fylle minnet og krasje, det er uunngåelig.

Hvor mange ganger loopen går før det er fullt kommer jo da an på hvor mange integere som lagres ved hver loop, og jeg har så lite peiling at jeg er usikker på hvor du begrenser dette, men normalt ville det vært noe sånt:

Kode:
Dim random(upper) As Integer
Random(i) = RandomClass.Next(1000000)

for å generere en integer mellom 0 og 1 mill, og uten å sette grenser er vel øvre integer 2147483647 eller noe sånt?

Jeg ville tro at du på et eller annet vis må begrense minnebruken, enten med variabler med færre integre, eller ved å bruke flytende punkt (som sikkert skrives som double i stedet for integer), eller ved å tømme minnet på en eller annen måte i loopen, Uten at jeg har noen gode forslag til hvordan du spesifikt går frem for å få til noen av de :confused:

Mer minne vil selvfølgelig gjøre at funksjonen kan kjøre lengre før den fyller opp det minnet som er tilgjengelig, og det kan også være at det er noe feil med allokeringen din av minne, men det kan jeg ingenting om, men du kan vel kontrollere minnet underveis, ville tippe det gjøres med VB's System Diagnostics Process:

Kode:
Dim p As System.Diagnostics.Process = _System.Diagnostics.Process.GetCurrentProcess
MemoryUse.Text &= _Format(p.WorkingSet64.ToString("N03")) & vbCrLf
Forskjellen på 64 og 32 bits prosessor er stort sett bare hvor mange tråder du kan kjøre samtidig, og det har liten betydning for å hindre den funksjonen i fylle opp minnet.

Prøvde et google søk, og fikk opp en haug med eksempler på Monte Carlo generering i VBA, som er nesten likt som VB, du kan prøve å implementere et av de scriptene i excel og se hvordan de oppfører seg i forhold til minne med de samme kriteriene for å få en pekepinn på hva som er mulig.
Jeg har testet Monte Carlo beregninger i C, men bare opp til rundt 1000 ganger, og jeg skulle tro det er rimelig spesielt dersom du virkelig har et behov for å kjøre dette 1mrd ganger, og det må da ta lang tid?
 

adeneo

Medlem
Hvis den krasjer på akkurat samme punktet, på omtrent nøyaktig 102 mill ganger, så er det sannsynligvis noe feil med scriptet, det er lite sannsynlig at begge deres maskiner har samme mengden ledig minne tilgjengelig, hvis ikke VB.net har en eller annen begrensing på dette innebygget eller noe slikt?
Det høres dog mer ut som en feil i koden, og den koden er vel såpass grei at det må vel være noen her som kan VB.net som kan se feilen.
 

Nutz

Med lem
prøvde eksempelet med Int64 (max 9,223,372,036,854,775,807) ikke der begrensningen ligger ser det ut som.
 

Stian O

Medlem
"W7 (64bit )her, 4 gig ram.. Krasjet på nøyaktig samme verdi her."

Flott! Da vet vi i alle fall at det er en begrensing ved operativsystemet, og at de det neppe vil hjelpe om jeg setter inn mer fysisk RAM.

Angående koden: Beklager at jeg ikke nevnte det eksplisitt - koden jeg la ved hadde til hensikt å være en uendelig loop slik at man kan observere når maskinen krasjer....
 

Stian O

Medlem
Fra MSDN
"The length of every dimension of an array is limited to the maximum value of the Integer data type, which is (2 ^ 31) - 1. However, the total size of an array is also limited by the memory available on your system. If you attempt to initialize an array that exceeds the amount of available RAM, the common language runtime throws an OutOfMemoryException exception."

2^31 er ca 2 milliarder, altså langt mer enn når den krasjer på 120 millioner.

Men at det skjer så tidlig har nok med REDIM PRESERVE å gjøre, da denne kopierer hele array'en på en treg og lite effektiv måte (noen andre kan sikkert forklarer dette bedre...)
 

Stian O

Medlem
Nutz: Her prøver jeg en litt annen vri og nå krasjer den (System.OutOfMemoryException) ved upper = 302,000,000. Opplever du det samme her også?

Private Sub testMemory2()
Dim upper As Integer = 0
Do
testMemory3(upper)
upper += 1000000
Loop
End Sub
Private Sub testMemory3(ByVal upper As Integer)
Dim testArray(upper) As Integer
End Sub
 

Nutz

Med lem
Litt "oppløftende" for deg kanskje.
Dersom jeg endrer til Byte, så får jeg 1,603,000,000.

altså denne " Dim testArray(upper) As byte"
 
Topp