maksymalna wielkość tablicy

0

Cześć, czy może mi ktoś napisać czy są jakieś ograniczenia odnośnie tworzenia tablic w danym języku (np. C++). Przykładowo: typ double zajmuje jakieś 8 bajtów (nie zawsze ale to nie istotne), czyli jeśli mam 4 GB RAM-u to każdy 1 GB może przechować jakieś 1000 000 000 bajtów czyli (10^9)/8 czyli każdy 1 GB może przechowywać jakieś 125 mln-ów liczb typu double czyli mając 4 GB mogę w przybliżeniu (nie biorę pod uwagę zajmowanej pamięci przez inne programy) tworzyć tablice mające 500 mln-ów elementów typu double np. double tablica[500][1000000];
Czy coś pominąłem? Czy są jakieś inne ograniczenia? Czy są jakieś niebezpieczeństwa związane z deklarowaniem tak dużych elementów?

0

Aż tak dobrze nie ma ;)

  1. Tablica zadeklarowana tak jak napisałeś nie zadziała. Czemu? Bo tak sie tworzy tablice na STOSIE, a stos zwykle ma ograniczenie do kilku(nastu/dziesięciu) MB. Na stosie nie powinno się trzymać takich dużych rzeczy. Od tego jest STERTA zarządzana w C++ za pomocą new, new[], delete i delete[]
  2. Chyba zapomniałeś o tym że system operacyjny i inne programy też potrzebują pamięci do życia :P Jak zaalokujesz 4GB to zacznie się masakra ze swapowaniem ;]
    Oprócz tego nie ma większych ograniczeń ani niebezpieczeństw. Przy czym jeśli alokujesz więcej pamieci niż potrzebujesz to ryzykujesz że nie będziesz w stanie łatwo zauważyć przypadkowego pisania po nie tej pamięci co trzeba.
0
Shalom napisał(a)

Aż tak dobrze nie ma ;)

  1. Tablica zadeklarowana tak jak napisałeś nie zadziała. Czemu? Bo tak sie tworzy tablice na STOSIE, a stos zwykle ma ograniczenie do kilku(nastu/dziesięciu) MB. Na stosie nie powinno się trzymać takich dużych rzeczy. Od tego jest STERTA zarządzana w C++ za pomocą new, new[], delete i delete[]
  2. Chyba zapomniałeś o tym że system operacyjny i inne programy też potrzebują pamięci do życia :P Jak zaalokujesz 4GB to zacznie się masakra ze swapowaniem ;]
    Oprócz tego nie ma większych ograniczeń ani niebezpieczeństw. Przy czym jeśli alokujesz więcej pamieci niż potrzebujesz to ryzykujesz że nie będziesz w stanie łatwo zauważyć przypadkowego pisania po nie tej pamięci co trzeba.

Dzięki za słuszną uwagę!
korzystanie z innych programów to tak jak napisałem: nie brałem pod uwagę zajmowanej pamięci przez inne programy i jestem świadom, że muszę trochę jej zostawić na inne rzeczy :)
Może to nie wyszło z kontekstu, ale pytałem bardziej pod ort! czy mogę śmiało tworzyć tablice chociaż na 100 mln-ów elementów (mając 4GB pozostanie jeszcze sporo miejsca na inne rzeczy :) ). Jest mi to potrzebne, bo planuję w przyszłości napisać program do data mining-u czyli to badania zależności w danych, których może być baaardzo dużo :). Chociaż z drugiej strony obróbka tak dużej ilości danych może trochę zająć i na pewno będę musiał się ograniczyć do znacznie mniejszej ilości danych.
Jeśli dobrze zrozumiałem to mogę zrobić tak jak myślałem, ale używając operatora new czyli będzie to w ten sposób:

int zm1 = 100, zm2 = 1000000;
double ** wsk;
wsk = new double *[zm1];
for(int i=0;i<zm1;i++)
wsk[i] = new double[zm2];

i będzie git?
później oczywiście zwolnić miejsce jak przestaniemy korzystać z tej tablicy...

pozdrawiam i dzięki za pomoc

0

Tak, będzie ok. Zresztą jaki problem sprawdzić? ;)

0

Dzięki wielki za pomoc! :)
miałem zamiar to sprawdzić za jakiś czas ale wolałem się upewnić czy nie będzie żadnych kłopotów :)
No i tak jak wspomniałem - słuszna uwaga, że musi być użyty operator new a nie standardowe zadeklarowanie tablicy.
pozdrawiam

0

weź jeszcze pod uwagę jedną rzecz: możesz mieć wolne i 4GiB, a nie uda się zaalokować nawet 1GiB. dlaczego? bo pojedyncza alokacja polega na zajęciu ciągłego obszaru pamięci, a tymczasem pamięć ulega fragmentacji (tak samo, jak dysk). z tego powodu powinieneś używać tablicy tablic, ponieważ o ile może nie być ciągłego bloku 1GiB, o tyle np. 1024 odrębne bloki o rozmiarze 1MiB znajdą się niemal na pewno.

0

Nawet jeśli nie ma ciągłego bloku, to Windows może się posłużyć swapem, i go sobie „wyczarować”.

Kiedyś udało mi się zaalokować 6 * 1 GB na 32-bitowym XP (1 GB RAM + 8 GB swapa, włączone PAE).

0
ŁF napisał(a)

weź jeszcze pod uwagę jedną rzecz: możesz mieć wolne i 4GiB, a nie uda się zaalokować nawet 1GiB. dlaczego? bo pojedyncza alokacja polega na zajęciu ciągłego obszaru pamięci, a tymczasem pamięć ulega fragmentacji (tak samo, jak dysk). z tego powodu powinieneś używać tablicy tablic, ponieważ o ile może nie być ciągłego bloku 1GiB, o tyle np. 1024 odrębne bloki o rozmiarze 1MiB znajdą się niemal na pewno.

Dzięki za kolejną uwagę!
Ale niestety nie wiem czy dobrze ją zrozumiałem. Czy mógłbyś rozwinąć to co masz na myśli? Jak mam to zorganizować?
Jeśli tworzę tablicę dwuwymiarową operatorem new to mam tablicę tablic -> czy o to Ci chodziło?
Jeśli dobrze Cię zrozumiałem to należałoby robić większy pierwszy wymiar niż drugi (tzn. żeby była tylko jedna duuuża tablica, która będzie przechowywać adresy do mniejszych tablic a nie odwrotnie tj. stosunkowo mała tablica z wieloma dużymi tablicami.

Ale co jeśli mam 1000 zmiennych a próba składa się z 1 mln-a obserwacji czyli mam tablicę tab[1000000][1000]?
Czy jest jakiś sposób, żeby się zabezpieczyć jakoś przed ewentualnymi błędami w alokacji?
Czy da się to jakoś ładnie zrobić, żeby, w razie większej ilości danych (gdyby brakowało RAM-u), dane były zapisane np. w pliku a żeby się do tego odnosić tak jak do zwykłych zmiennych czyli tablica[x][y]? Coś kojarzę takiego ale nie pamiętam za bardzo skąd i jak to było dokładnie - ale chyba jest taka możliwość.

Co jeśli tablic będzie mimo wszystko dużo i będą bardzo długie - czy da się jakoś inaczej zabezpieczyć przed ewentualnymi błędami?

Pozdrawiam i dziękuję za pomoc!

0

Chodzi o to że jak chcesz zrobić new cośtam[X] to próbujesz zaalokować CIĄGŁY kawałek pamięci o dlugości sizeof(coś)*X.
Jeśli np. jest to 1GB to system operacyjny próbuje znaleźć 1GB ciągłego, wolnego obszaru. Może być tak że masz wolne 4GB, ale w kawałkach po 512 MB i alokacja się nie powiedzie :)

0
MisiekW napisał(a)

Ale niestety nie wiem czy dobrze ją zrozumiałem. Czy mógłbyś rozwinąć to co masz na myśli? Jak mam to zorganizować?
Jeśli tworzę tablicę dwuwymiarową operatorem new to mam tablicę tablic -> czy o to Ci chodziło?
Jeśli dobrze Cię zrozumiałem to należałoby robić większy pierwszy wymiar niż drugi (tzn. żeby była tylko jedna duuuża tablica, która będzie przechowywać adresy do mniejszych tablic a nie odwrotnie tj. stosunkowo mała tablica z wieloma dużymi tablicami.
nie. wszystko jedno który rozmiar jaki będzie, ważne, żeby żaden nie przekroczył kilkudziesięciu MB (pamiętaj, że tablica wskaźników do tablic też ma swój rozmiar).

MisiekW napisał(a)

Ale co jeśli mam 1000 zmiennych a próba składa się z 1 mln-a obserwacji czyli mam tablicę tab[1000000][1000]?
masz taką tablicę, jaką sobie utworzysz. ja na Twoim miejscu utworzyłbym klasę działającą jak tablica, a wewnątrz niej oprogramował działanie na mniejszych blokach pamięci. przy czym "mały" to okolice kilkudziesięciu MB.

MisiekW napisał(a)

Czy jest jakiś sposób, żeby się zabezpieczyć jakoś przed ewentualnymi błędami w alokacji?
tak. oprogramować je.

MisiekW napisał(a)

Czy da się to jakoś ładnie zrobić, żeby, w razie większej ilości danych (gdyby brakowało RAM-u), dane były zapisane np. w pliku a żeby się do tego odnosić tak jak do zwykłych zmiennych czyli tablica[x][y]? Coś kojarzę takiego ale nie pamiętam za bardzo skąd i jak to było dokładnie - ale chyba jest taka możliwość.
windows ma coś takiego. nazywa się pamięć wirtualna i pozwala na zwiększenie przestrzeni adresowej pamięci kosztem ewentualnego spadku wydajności. masz za mało ram? zwiększ rozmiar swapa (pod w7: aplet "zaawansowane" ustawienia systemu->zakładka zaawansowane->pamięć wirtualna->zmień).
zresztą jeśli dostęp do tablicy ubierzesz w klasę, to "przedłużenie" ramu plikiem będzie w miarę proste. windows ułatwia sprawę dając mechanizm mapowania zawartości pliku jako kawałka pamięci (http://en.wikipedia.org/wiki/Memory-mapped_file). jednak myślę, że takie mechanizmy nie będą Ci potrzebne, kilka GB pamięci w tych czasach to nieduży koszt.

MisiekW napisał(a)

Co jeśli tablic będzie mimo wszystko dużo i będą bardzo długie - czy da się jakoś inaczej zabezpieczyć przed ewentualnymi błędami?
tak. new zwróci null. jak to oprogramujesz, to już Twoja sprawa.

0
Shalom napisał(a)

Chodzi o to że jak chcesz zrobić new cośtam[X] to próbujesz zaalokować CIĄGŁY kawałek pamięci o dlugości sizeof(coś)*X.
Jeśli np. jest to 1GB to system operacyjny próbuje znaleźć 1GB ciągłego, wolnego obszaru. Może być tak że masz wolne 4GB, ale w kawałkach po 512 MB i alokacja się nie powiedzie :)

No właśnie domyśliłem się tego, ale jak się przed tym bronić - czy jest jakiś sposób?
Azarien pisał coś o swapie, ale czy jest możliwość jakiegoś innego zabezpieczenia przed tym? Bo muszę się liczyć z tym, że nie zawsze on zadziała.
Co jeśli np. rzeczywiście potrzebowałbym ten 1GB pamięci w jednej tablicy a miałbym posiekane miejsce, że max mogłoby być 512 MB?
Myślałem o ewentualnym zapisaniu danych na dysku i jakoś się do nich odnosić tak jak do zwykłych danych w pamięci - w razie niepowodzenia alokacji. Jednak takie pobieranie danych z dysku jest znacznie wolniejsze więc nie wiem czy jest to dobry pomysł... Pozostaje również pytanie jak takie coś zrobić? chyba trzeba byłoby stworzyć jakąś klasę i przeładować operator [][] ale brakuje mi szczegółów takiej operacji...
Jednak takie rozwiązanie z zapisaniem danych na dysku rozwiązuje również inny problem - gdyby ktoś korzystał z mojego programu a miałby np. do dyspozycji 1-2GB pamięci to nie musiałby się martwić, że mu jej zabraknie :)

0

Jeżeli program jest 64-bitowy to w zasadzie nie trzeba się o to martwić, bo 4GB blok pamięci praktycznie zawsze się znajdzie.

0
ŁF napisał(a)

masz taką tablicę, jaką sobie utworzysz. ja na Twoim miejscu utworzyłbym klasę działającą jak tablica, a wewnątrz niej oprogramował działanie na mniejszych blokach pamięci. przy czym "mały" to okolice kilkudziesięciu MB.

To brzmi bardzo ciekawie :) ale czy mógłbyś mi pomóc i rozwinąć trochę tą koncepcję bo nie wiem za bardzo jak się za to zabrać :( Może już miał ktoś podobny problem i opisał to w necie?
Czy dobrze myślę:
Jak ma to być duża tablica jednowymiarowa np. tablica[1000000] to można byłoby zrobić klasę class tab, która utworzy tablicę dwuwymiarową np. new tablica[1000][1000] i jak chcemy się odnieść do tab[2000] to wyszukujemy go z tej dwu wymiarowej tablicy - nie pamiętam już jak to było (jak są te elementy zapisane w tablicy dwu wymiarowej) - ale z tym sobie już poradzę!

Podobnie, chociaż jeszcze nie wiem jak miałoby to wyglądać dla tablicy dwu wymiarowej... :/

0

Przede wszystkim przy takiej ilości pamięci, trzeba użyć new, albo malloc/calloc. Nie można tworzyć takiej zmiennej jako lokalnej na stosie, bo program wyleci w kosmos.
Można natomiast mieć taką dużą zmienną lokalną, ale to nie jest dobry pomysł.
Po alokacji sprawdzaj czy wskaźnik nie jest NULL — jeśli jest, to pamięci zabrakło, nic na to nie poradzisz, ale możesz wyświetlić sensowny komunikat.

To dotyczy zarówno 32 jak i 64 bitów.

Problem z dużymi blokami pamięci jest taki, że masz większą szansę powodzenia czterech new za każdym razem po 1 gigabajcie, niż jeden new na 4 GB od razu.
Swap ci w niczym nie przeszkadza — gdyby go nie było, miałbyś jeszcze mniejszą szansę powodzenia.

która utworzy tablicę dwuwymiarową np
odróżniaj tablicę dwuwymiarową od tablicy tablic. to drugie to to, czego ci trzeba.

0
Azarien napisał(a)

Przede wszystkim przy takiej ilości pamięci, trzeba użyć new, albo malloc/calloc. Nie można tworzyć takiej zmiennej jako lokalnej na stosie, bo program wyleci w kosmos.
Można natomiast mieć taką dużą zmienną lokalną, ale to nie jest dobry pomysł.
Po alokacji sprawdzaj czy wskaźnik nie jest NULL — jeśli jest, to pamięci zabrakło, nic na to nie poradzisz, ale możesz wyświetlić sensowny komunikat.

To dotyczy zarówno 32 jak i 64 bitów.

Problem z dużymi blokami pamięci jest taki, że masz większą szansę powodzenia czterech new za każdym razem po 1 gigabajcie, niż jeden new na 4 GB od razu.
Swap ci w niczym nie przeszkadza — gdyby go nie było, miałbyś jeszcze mniejszą szansę powodzenia.

która utworzy tablicę dwuwymiarową np
odróżniaj tablicę dwuwymiarową od tablicy tablic. to drugie to to, czego ci trzeba.

Dzięki za odpowiedź, ale chyba w takim razie nie rozumiem czym jest tablica tablic - jeśli nie tablicą dwu wymiarową czyli tablicą, której elementami są inne tablice to czym? Chyba, że chodzi Ci o to, żeby utworzyć tablicę dwu wymiarową operatorem new czyli jedna tablica będzie miała wskaźniki do pozostałych (mniejszych) tablic.

To, że tak duże tablice deklaruje się operatorem new już wiem (było o tym wspomniane na samym początku) - w moich przykładach piszę skrótowo w domyśle, że chodzi mi o tablice new.

Moje pytanie dot. właśnie jak zorganizować takie alokowanie 4 tablic zamiast jednej 4 GB.
jeśli dobrze rozumiem to można to zrobić w ten sposób, że zamiast tworzyć tablicę[4GB] można zrobić tablicę[4][1GB] (oczywiście operatorem new - czyli będą 4 wskaźniki do 4 tablic[1GB])
można również zrobić klasę, która będzie działać tak jak tablica jedno wymiarowa ale będzie zawierać w sobie tablicę dwu wymiarową (w której będzie przechowywać dane) czyli 4 tablice po 1GB.
Jeśli dobrze pamiętam odwoływanie się do elementów tablicy dwu wymiarowej tak jak w tablicy jednowymiarowej jest w taki sposób: Max_YX+Y, gdzie Max_Y to maksymalny wymiar drugiego wymiaru tablicy, x to index pierwszego wymiaru a y to index drugiego wymiaru. Czyli tablica[X][Y] = tablica[Max_YX+Y] //chociaż pewny nie jestem (można to łatwo sprawdzić i zrobię to w domu)

Ale nie wiem czy Wam/Tobie o to chodziło?

0

W przypadku alokacji dynamicznej nie ma tablic wielowymiarowych. Są tylko tablice tablic :)
Tablica wielowymiarowa (statyczna) ma taki minus że musi być ciągłym obszarem pamięci. Jeśli masz:

int** tablica = new int*[100];
for(int i=0;i<100;i++){
  tablica[i]=new int[1000];
}

To każda z naszych 100 tablic może leżeć w zupełnie innym miejscu w pamięci :)

0

Chyba, że chodzi Ci o to, żeby utworzyć tablicę dwu wymiarową operatorem new czyli jedna tablica będzie miała wskaźniki do pozostałych (mniejszych) tablic.
Dokładnie o to chodzi.

w moich przykładach piszę skrótowo w domyśle
To przestań pisać skrótowo, bo inni się nie domyślą tego samego.

Moje pytanie dot. właśnie jak zorganizować takie alokowanie 4 tablic zamiast jednej 4 GB.
Wszystko jedno — możesz zrobić własną klasę, możesz nie robić.

Jeśli dobrze pamiętam odwoływanie się do elementów tablicy dwu wymiarowej tak jak w tablicy jednowymiarowej jest w taki sposób: Max_Y*X+Y
Teraz znów piszesz o tablicy wielowymiarowej, a nie o tablicy zagnieżdżonej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1