[C#] Dictionary - limit pojemności


(CzoQś) #1

Witam,

Mam pytanie odnośnie wykorzystania całych zasobów pamięci ram przez aplikację napisaną w Visual C# 2010 Express.

Wykorzystuje ona "Dictionary" do przechowywania pewnych danych.

Posiadam Windows 7 x64 i 4GB ram - w wersji 32bitowej aplikacji maksymalnie mogłem dodać około 45mln rekordów do słownika (~1.6GB ramu zajmował proces). Postanowiłem przekompilować do x64 - udało się "wcisnąć" 60mln rekordów (~2.1GB) i dalej nie chce już iść krzycząc że brakuje pamięci..

Postanowiłem więc uruchomić aplikację na kompie z 8GB pamięci i o dziwo ta sama sytuacja co przy 4GB - jedynie 60mln wchodzi do słownika...

Coś wygooglowałem o stosowaniu LARGEADDRESSAWARE, ale nie wiem jak i gdzie to dodać przy wersji Express...

Czy jest jakaś szansa na wykorzystanie większej ilości ramu niż tylko 2GB?

Pozdrawiam


(kowal.luk) #2

w wersji express raczej nie, ograniczenie


(Djluki) #3

Z tego co pamiętam to wersja Express nie ma żadnych ograniczeń na pamięć.

Visual Studio po prostu nie potrafi zaadresować więcej niż 2GB pamięci. Więc musisz mu to kazać zrobić.

  1. Robisz kopię zapasową visual studio - plik: devenv.exe

  2. W katalogu: {VisualStudioRoot}\Common7\IDE\ wykonujesz polecenie:

editbin /LARGEADDRESSAWARE devenv.exe

I program powinien zacząć wykorzystywać więcej niż 2 GB pamięci - jeśli oczywiście masz jej tyle wolne :stuck_out_tongue:


(CzoQś) #4

Problem w tym, że w podanej lokalizacji brakuje pliku devenv.exe, a polecenie editbin nie jest rozpoznawane...


(Tomek Matz) #5

http://msdn.microsoft.com/en-us/library/ms241064.aspx

Możesz zrobić tak:

1) Sprawdź, czy uda Ci się zwiększyć ilość elementów w tym słowniku, gdy zamienisz typ tego obiektu ze struct na class oraz klucz z long na int lub uint (oczywiście w przypadku aplikacji 64-bitowej). Wykonaj ten drobny test i daj znać o wynikach (możesz też przy okazji pokazać kod tej struktury).

2) Zamień Dictionary na List z predefiniowaną ilością elementów podawaną w konstruktorze (wówczas na pewno uda Ci się upchnąć więcej elementów). Taka zamiana ma sens, bo dla właściwości Item mamy:

http://msdn.microsoft.com/en-us/library/0ebtbkkc.aspx

Innych rozwiązań nie widzę (co nie znaczy, że ich nie ma).


(CzoQś) #6

Oto elementy kodu związane z tworzeniem słownika:

public struct Transpose

        {

            public int val { get; set; }

            public int bound { get; set; }

            public int depthTT { get; set; }

        }



        static int pojemnosc_TT = 60000000;

        public static Dictionary transpozycja = new Dictionary(pojemnosc_TT);

Zmiana klucza z long na int raczej nie wchodzi w grę - każdy klucz typu long to pewna liczba generowana według planszy 15x15 elementów gdzie mogą wystąpić 3 stany na każdej pozycji - ilość kombinacji jest olbrzymia, a mi zależy na jak najmniejszej ilości kolizji. Próbowałem zamiany struct na class i otrzymałem dziwne wyniki: 1) w przypadku struct gdy zadeklaruję w kodzie zbyt dużą wartość pojemnosc_TT to aplikacja wcale się nie uruchomi (jak już się uruchomi to działa be błędów) 2) w przypadku class aplikacja uruchamiała się nawet przy pojemnosc_TT=85000000, ale w trakcie obliczeń wywalało błędy z jakimiś adresami pamięci 3) w przypadku struct aplikacja zaraz po uruchomieniu zajmowała w pamięci około 250MB 4) w przypadku class aplikacja zaraz po uruchomieniu zajmowała ponad 2GB 5) zarówno dla struct jak i class w trakcie gry następowało stopniowe zwiększanie zajętości pamięci (dla class dochodziło do około 2.5GB i wywalało błąd) 6) zmieniłem dla class inicjowanie słownika (bez deklarowania pojemności):

public static Dictionary transpozycja = new Dictionary();

...aplikacja na starcie zajmowała około 7MB i dalej rosła zajętość w trakcie gry

7) niestety class nawet dla 60000000 generowało po pewnym czasie błąd i aplikacja musiała zostać zamknięta - wniosek struct działa o wiele stabilniej

Z uwagi na fakt, że słownik stosuję do zapamiętywania obliczonych w trakcie gry stanów planszy (raz wyliczony stan nie musi być ponownie przeliczany) - wymagam możliwie najszybszego wyszukiwania klucza - lista będzie tu sporo wolnijesza wiec wolę pozostać przy słowniku...


(somekind) #7

Pytanie zasadnicze - czemu chcesz mieć taki ogromny obiekt?

Nie bredź.

Co ma IDE do działania programu w nim napisanego?


(Tomek Matz) #8

Maksymalna wartość int to 2,147,483,647 (int.MaxValue)

Maksymalna wartość uint to 4,294,967,295 (uint.MaxValue)

Czy ta pewna generowana liczba faktycznie może mieć większą wartość?

Dlaczego wolniejsza? Sprawdzałeś to? Wkleiłem Ci przecież cytat ze strony msdn, że pobranie danego elementu z listy korzystając z indeksu, to operacja o złożoności O(1) (czyli takiej samej jak w przypadku pobrania wartości ze słownika korzystając z klucza).

Z użyciem listy chodzi mi tutaj o to, że jeśli na starcie wiesz, z jakiej liczby obiektów będzie się ona składać, to możesz traktować indeks jak klucz (nawet mógłbyś pomyśleć, czy nie sprawdzi się tutaj zwykła tablica). Lista ta przechowywałaby albo klasy albo struktury, które mogą przyjmować null-e (typ nullable). Jeśli pod danym indeksem będzie null, tzn. że dla tego klucza nie została jeszcze przypisana żadna wartość (taki odpowiednik metody ContainsKey). Jeśli pod danym indeksem nie będzie null-a, tzn. że dla tego klucza została już przypisana jakaś wartość. Jeszcze raz jednak podkreślam. To ma sens wtedy, gdy na wstępie, wiesz z jakiej liczby obiektów będzie się składać ta lista i zainicjalizujesz ją null-ami. W innym wypadku musisz użyć słownika.

BTW jeśli to jest gra, to nie może być tak, że ma ona aż tak gigantyczne zapotrzebowanie na pamięć operacyjną. No chyba, że będzie to gra dekady. Wtedy wszystko da się wybaczyć.


(CzoQś) #9

Może zacznę od początku - tworzę sobie grę gomoku (takie kółko i krzyżyk tylko na większej planszy) z możliwością gry z komputerem.

AI komputera wykorzystuje algorytm minimax z cięciami A-B i jako optymalizację dodałem tablicę transpozycji w formie słownika.

Im więcej uda się w trakcie gry zachować raz przeliczonych pozycji tym większe można uzyskać przyspieszenie - w trakcie gry generowanych jest bardzo dużo pozycji powtarzających się i właśnie wtedy słownik bez zbędnego liczenia zwróci mi potrzebną wartość...

Dodatkowo tworzę sobie bazę przeliczonych ruchów - taka baza debiutów połączona z bardzo prymitywnym sposobem uczenia.

Dla zobrazowania przestrzeni stanów na planszy 15x15 można w przybliżeniu podać: 3^225 więc nawet typ long przy tym wymięka...

Nie będę mógł korzystać z pobrania elementu z listy przez indeks, bo musiałbym wcześniej wygenerować całą listę możliwych stanów Lista[(long)klucz].wartosc a jest to niewykonalne..

Tak wielka transpozycja tworzona wyłącznie na czas generowania bazy początkowych ruchów - po zapamiętaniu pewnej ich liczby można zmniejszyć słownik do około 5-8mln.

//==========================================================

Zainstalowałem wersję VS 2010 Ultimate...

Jest plik devenv.exe...

Brak pliku EDITBIN.EXE - skąd to wziąć?

186076d57d6cc8d3gen.jpg

//==========================================================

Sprawa z EDITBIN wyjaśniła się...

Okazuje się, że VS ma własny wiersz poleceń i to z niego trzeba wklepać to polecenie...

Niestety przy moich 4GB ramu nie ma różnicy - tak samo mogę odpalić aplikację z około 60mln rekordów w słowniku...

Dodatkowo poleceniem editbin przejechałem wynikowy plik gry - wysłałem koledze co ma 8GB ramu i zobaczę czy u niego teraz uda się odpalić (przygotowana wersja 70mln - wcześniej nie działało mu).


(somekind) #10

devenv.exe jest zawsze, przecież to plik, który włącza Visual Studio.

Tak czy siak, przemyśl swój algorytm, bo trudno nie zauważyć, że coś z nim jest nie tak.


(CzoQś) #11

Z tego co się zdążyłem zorientować w wersji express plik uruchomieniowy C# występuje pod zmienioną nazwą - dlatego nie mogłem go zlokalizować...

Dzięki za zainteresowanie - mam nadzieję, że w przyszłych wersjach VS nie będzie takiego limitu wykorzystania pamieci.

Pozdrawiam


(somekind) #12

Pod jaką niby zmienioną nazwą?

Zrozum, że ten "limit" nie od VS zależy. ;]


(CzoQś) #13

VCSExpress.exe zamiast devenv.exe