Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C#] Grootste vrije geheugen blok opvragen

Pagina: 1
Acties:

  • djexplo
  • Registratie: Oktober 2000
  • Laatst online: 27-10 15:31
In c# is de grootste mogelijke array gelijk aan het grootste continue vrije geheugen blok. Graag wil ik van te voren weten hoe groot dit "largest continuous memory block" is zo dat ik niet halverwege het renderen van een 3D volume met exceptions zit...

Voor het verkrijgen van het "largest continuous memory block" heb ik al gekeken naar:
System.Runtime.MemoryFailPoint, CIM_OperatingSystem en andere WMI en CIM libraries, maar nog niet de oplossing gevonden. Dus als iemand een nette oplossing weet :) ?

Mijn huidige (tijdelijke) oplossing:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
       private int LargestContinousblock()
       {
            int succes_size = 0; // Largest array succes in(MB) 
            int size = 1000; // Start test 1000MB
            for (int i = 0; i < 15; i++) // Find largest possible array 
            {
                GC.Collect();
                if (Continousblock_test(size)) 
                { 
                    size += (size / 2); if (size > succes_size) succes_size = size; 
                }
                else size = size / 2; 
            }
            GC.Collect();
            return succes_size;
        }
        private static Boolean Continousblock_test(int size)
        {
            try { byte[] testarray = new byte[size * 1048576]; }
            catch { return false; }
            return true;
        }

'if it looks like a duck, walks like a duck and quacks like a duck it's probably a duck'


  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 31-10 11:58
Ik weet niet waar je dit doet, maar het lijkt me niet heel wenselijk om regel 7 heel vaak uit te voeren tijdens het renderen...

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Wat dacht je van een MemoryStream? Die kan namelijk (ook) overweg met gefragmenteerde geheugen blokken. Omdat bijvoorbeeld de StringBuilder intern gebruik maakt van een MemoryStream, heeft deze minder resources nodig bij veelvuldige string manipulaties. Zou je een 'normale' string gebruiken moet deze opnieuw geheugen alloceren als het resultaat meer of minder tekens bevat. Als het aantal tekens gelijk blijft is er geen extra allocatie nodig. Omdat managed strings niet null terminated zijn kunnen de overige bytes bij minder tekens ook niet met null tekens opgevuld (padding) worden.

Maar als je echt zelf geheugen wilt alloceren en vrij gegeven kun je misschien beter naar c++/cli kijken ipv C#.

If it isn't broken, fix it until it is..


  • djexplo
  • Registratie: Oktober 2000
  • Laatst online: 27-10 15:31
MemoryStream is jammer genoeg niet mogelijk om dat ik de data aan openGL libraries voer die een memory blok verwachten, maar wel een mooie functie :) .

'if it looks like a duck, walks like a duck and quacks like a duck it's probably a duck'


  • ? ?
  • Registratie: Mei 2007
  • Niet online

? ?

lama snap 't ni

[ Voor 105% gewijzigd door ? ? op 04-04-2008 15:59 ]


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Waarschijnlijk mis je iets in je redenering...

Je hebt virtueel en fysisch geheugen. Een applicatie krijgt virtueel geheugen toegewezen, wat slechts een minimale administratie is. Eens je dat geheugen begint te gebruiken worden er page faults gegenereerd en worden voor die adressen, per blok van 4k op de meeste architecturen, fysisch geheugen gealloceerd.

De mapping tussen fysisch en virtueel geheugen moet niet lineair zijn: fysisch(virtueel0+4k) != fysisch(virtueel0)+4k.

Bovendien zou ik gaan verwachten dat als de CLR geen virtueel aaneensluitend blok van significante grootte kan alloceren, hij nieuw geheugen aan het OS zal aanvragen.

ASSUME makes an ASS out of U and ME


Verwijderd

Kun je niet met List<byte> b en b.Capacity de grootte aanvragen? Bij een exception weet je dat het geen zin meer heeft. Ik neem tenminste aan dat je weet hoe groot je data block uiteindelijk wordt?

Edit:
Ik zie dat je dat al doet...

[ Voor 37% gewijzigd door Verwijderd op 04-04-2008 20:14 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
djexplo schreef op vrijdag 04 april 2008 @ 15:16:
MemoryStream is jammer genoeg niet mogelijk om dat ik de data aan openGL libraries voer die een memory blok verwachten, maar wel een mooie functie :) .
Die hebben vast geen memory block van 1024+MB nodig?

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • djexplo
  • Registratie: Oktober 2000
  • Laatst online: 27-10 15:31
MSalters schreef op vrijdag 04 april 2008 @ 22:31:
[...]

Die hebben vast geen memory block van 1024+MB nodig?
Nee iets van 512MB aan MRI data (512 x 512 x 512 x 4) en dat vormt vaak al een probleem. Bijvoorbeeld in Matlab is het opvragen van het grootste vrije blok wel mogelijk:
Afbeeldingslocatie: http://www.k-zone.nl/matlab.png

'if it looks like a duck, walks like a duck and quacks like a duck it's probably a duck'


  • ? ?
  • Registratie: Mei 2007
  • Niet online

? ?

gewoon een of andere memory utility aanroepen en uitlezen ? Process.Start en dan de output afvangen
zoek eens op memory tooltjes, mem.exe geeft iest te weinig info denk ik

[ Voor 62% gewijzigd door ? ? op 05-04-2008 12:03 ]


  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
Ik weet niet of er een kant en klare functie voor is, maar ik vind het algoritme een beetje vreemd. Ik zou eerder een "min" en "max" waarde bijhouden, waarin ik een onder- en bovengrens bijhou. Deze code heb ik niet uitgeprobeerd, maar kijk even naar het idee.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
       private int LargestContinousblock()
       {
            int min = 0;
            int max = 2000;
            int huidig;

            while (min < (max-1)) /* Hier een beetje uitkijken, ivm integer afronding */
            {
                GC.Collect();

                huidig = (min + max) / 2;

                if (Continousblock_test(huidig)) 
                {
                    min = huidig;
                }
                else
                {
                   max = huidig;
                }       
            }

            return huidig;
        }
   

[ Voor 3% gewijzigd door KopjeThee op 05-04-2008 12:29 ]


  • djexplo
  • Registratie: Oktober 2000
  • Laatst online: 27-10 15:31
KopjeThee schreef op zaterdag 05 april 2008 @ 12:13:
Ik weet niet of er een kant en klare functie voor is, maar ik vind het algoritme een beetje vreemd. Ik zou eerder een "min" en "max" waarde bijhouden, waarin ik een onder- en bovengrens bijhou. Deze code heb ik niet uitgeprobeerd, maar kijk even naar het idee.

C#:
1
2
 
...   
Jou code is inderdaad meer straightforward, bedankt ...

'if it looks like a duck, walks like a duck and quacks like a duck it's probably a duck'


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 20:02
Mathlab implementeert waarschijnlijk zelf z'n allocatie (en mapping op de virtuele adresruimte) vandaar dat 'ie kan zeggen hoeveel er nog vrij is. In het algemeen is dat niet zo makkelijk, zeker als je gebruik maakt van de allocatiefuncties van Windows. Je moet dan waarschijnlijk zelf gaan zitten rekenen op basis van limieten van Windows en de allocaties die je al gedaan hebt.

Bedenk ook wat H!GHGuY net zei: vrije adresruimte heeft nagenoeg niets te maken met vrij geheugen. Op een 64-bits systeem is vrije adresruimte nooit een issue (simpelweg omdat de adresuimte veel groter is dan de hoeveelheid geheugen die je zinnigerwijs zou kunnen alloceren). Alleen in een 32-bits omgeving is het zinnig je af te vragen of er nog wel voldoende aaneengesloten geheugen vrij is. Ik kan me voorstellen dat er daarom in C# geen methoden zijn om dit soort gegevens op te vragen, want in een 64-bit omgeving zijn ze niet relevant.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-11 23:43

.oisyn

Moderator Devschuur®

Demotivational Speaker

riezebosch schreef op vrijdag 04 april 2008 @ 14:39:
Ik weet niet waar je dit doet, maar het lijkt me niet heel wenselijk om regel 7 heel vaak uit te voeren tijdens het renderen...
Je wilt sowieso geen memory allocations doen tijdens het renderen 8)7

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

de enige juiste manier om niet halverwege met exceptions te zitten is pre-allocatie van je geheugen.

Bovendien heb je in C# voor object-arrays helemaal geen contiguous memory nodig, aangezien voor zover ik weet enkel de references in de array komen (voor ref types). Verder kunnen de individuele objecten overal in het geheugen zitten. De CLR memory manager kan theoretisch zelfs objecten verplaatsen door de references aan te passen (hoewel ik niet weet of dit ook geimplementeerd is) of door double referencing.
Voor value types zijn er anders ook genoeg zinnige oplossingen te bedenken om rond zo'n beperking te werken.

Neem als voorbeeld die memorystream.

Je kan bvb ook volgende strategie toepassen:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class MemoryFragment<T> where T:struct
{
   private uint offset = 0;
   private T[] array;
   public T this[uint i] { get { return array[i-offset]; } set { array[i-offset] = value; }
}

class MemoryArray<T> where T:struct
{
   private const uint FRAGMENTSIZE = 100*1024*1024;
   private SortedList<uint, MemoryFragment> fragments; // key = offset

   private MemoryFragment BinarySearch(uint address) { /* */ }
   private MemoryFragment RequestMemoryFragment(uint address)
   {
      MemoryFragment ret = BinarySearch(address);
      if (ret == null)
      {
         ret = new MemoryFragment(address / FRAGMENTSIZE, FRAGMENTSIZE);
         fragments.Add(address/FRAGMENTSIZE, ret);
      }
      return ret;
   }
   public T this[uint i]
   {
      get
      {
         return RequestMemoryFragment(i)[i];
      }
      set
      {
         RequestMemoryFragment(i)[i] = value;
      }
   }
}


afhankelijk van welke performance criteria en belangrijker welke geheugen criteria je hebt zijn er nog tal van optimalisatie mogelijkheden, bvb:
- variabele size geheugen wanneer er outofmemory excepties optreden. (telkens blocksize halveren en opnieuw aanvragen). Brengt wel iets meer boekhouding met zich mee. Eventueel met een minimum grens om te grote geheugen fragmentatie tegen te gaan. (Als er minder dan 10MB alloceerbaar is geraak je ook gewoonweg zonder geheugen en kun je beter stoppen voor je applicatie op een ander punt crasht)
- linked list ipv sortedlist. Door zowel een begin-of-memory en end-of-memory bij te houden kun je snel van vooraan of achteraan beginnen zoeken. Dan heb je maximaal fragment/2 searches maar door je memory fragment size maximaal te houden is dit nog steeds een klein getal.
- B-tree achtige implementaties met nodes en leafs.
- "Sparse memory" model: Het stukje code dat ik hierboven beschrijf heeft dit reeds. Door niet te vereisen dat alle addressen aanwezig zijn, kun je gaten hebben in je geheugenarray. Als je dit niet wil moet je in de RequestMemoryFragment bij een nieuwe allocatie ook alle voorgaande fragmenten sinds het laatste fragment alloceren. Zo kan je garanderen dat alle addressen beschikbaar zijn.
- Pre-allocatie van je memoryarray. Deze code doet alles ad-hoc. Bij pre-allocatie maak je je array op de juiste grootte vooraf aan.
- Afhankelijk van of de CLR dit reeds doet of niet, kun je alle elementen in je array de default waarde assignen (ala memset() uit C) om zeker te zijn dat er ook fysisch geheugen is gealloceerd voor elk virtueel adres.
- etc. etc.

[ Voor 3% gewijzigd door H!GHGuY op 06-04-2008 11:00 ]

ASSUME makes an ASS out of U and ME


  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
H!GHGuY schreef op zondag 06 april 2008 @ 10:57:
De CLR memory manager kan theoretisch zelfs objecten verplaatsen door de references aan te passen (hoewel ik niet weet of dit ook geimplementeerd is) of door double referencing.
Er wordt een (generational) stop-and-copy garbage collector gebruikt, dus referenties worden zeerzeker aangepast.

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]

Pagina: 1