Forum Informatyka UJ forum Strona Główna Informatyka UJ forum
Rocznik 2005 - czyli najlepsze forum w sieci
 
 FAQFAQ   SzukajSzukaj   UżytkownicyUżytkownicy   GrupyGrupy   GalerieGalerie   RejestracjaRejestracja 
 ProfilProfil   Zaloguj się, by sprawdzić wiadomościZaloguj się, by sprawdzić wiadomości   ZalogujZaloguj 

C++ - wypisanie ilości zaalokowanej pamięci

 
Napisz nowy temat   Odpowiedz do tematu    Forum Informatyka UJ forum Strona Główna -> Informatyka
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
cheater_
Orajt:)



Dołączył: 28 Lut 2006
Posty: 1022
Przeczytał: 0 tematów


PostWysłany: Sob 16:53, 28 Paź 2006    Temat postu: C++ - wypisanie ilości zaalokowanej pamięci

Wiecie może jak w C++ wypisać ilość wykorzystywanej w danym momencie pamięci ?
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
exeman
Mistrz grilla



Dołączył: 03 Lut 2006
Posty: 1603
Przeczytał: 0 tematów

Skąd: znienacka

PostWysłany: Sob 20:55, 28 Paź 2006    Temat postu:

Hm, dobre pytanie - jesli kodzisz windowsowego koda, to mozesz skozystac z jakis funkcji winapi (GetProcessMemoryInfo chyba, lub jakies HeapWalk'i) co zwroca pamiec zajmowana przez proces, natomiast jesli chodzi o ASD to kodzimy tam surowo jakby pod dosa, wiec raczej nie bardzo. Oczywiscie nie da sie tego zrobic przenosnie.
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Stefan
pijak



Dołączył: 22 Lis 2005
Posty: 173
Przeczytał: 0 tematów


PostWysłany: Pon 1:22, 30 Paź 2006    Temat postu:

Zaalokowanej jak? Jeśli dynamicznie, to można przeładować globalne (choć lepiej robić to dla klas) operatory new i delete:

Kod:
#include <memory>
#include <iostream>
#include <cstdlib>
#include <stdexcept>
using namespace std;

class DynMemInfo
{
    public:
        static size_t allocated()
        {
            return memSize;
        }
    private:
        friend void* operator new(size_t count) throw(std::bad_alloc);
        friend void operator delete(void* ptr) throw ();
        DynMemInfo();
        static size_t memSize;
};

size_t DynMemInfo::memSize = 0;


void* operator new(size_t count) throw(std::bad_alloc)
{
    DynMemInfo::memSize += sizeof(size_t) + count;
    void* mem = malloc(sizeof(size_t) + count);
    // tutaj przydaloby sie jakies sprawdzanie, czy alokowanie sie powiodlo...
    *static_cast<size_t*>(mem) = sizeof(size_t) + count;
    return static_cast<char*>(mem) + sizeof(size_t);
}

void operator delete(void* ptr) throw ()
{
    void* mem = static_cast<char*>(ptr) - sizeof(size_t);
    DynMemInfo::memSize -= *static_cast<size_t*>(mem); 
    free(mem);
}

void* operator new[](size_t count) throw(std::bad_alloc)
{
    return operator new(count);
}

void operator delete[](void* ptr) throw()
{
    operator delete(ptr);
}

int main()
{
    int* ptr = new int(10);
    cout << DynMemInfo::allocated() << endl;
    delete ptr;
    cout << DynMemInfo::allocated() << endl;
    int* ptr2 = new int[100];
    cout << DynMemInfo::allocated() << endl;
    delete[] ptr2;
    cout << DynMemInfo::allocated() << endl;   
}

Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
m^2
pijak



Dołączył: 15 Mar 2006
Posty: 62
Przeczytał: 0 tematów

Skąd: Katowice

PostWysłany: Pon 10:40, 30 Paź 2006    Temat postu:

To nie działa. Systemowy operator new zwraca kawałek pamięci rozmiaru co najmniej takiego, jak trzeba. Więc memSize będzie tylko ograniczeniem od dołu na używaną pamięć.
A pamięć zaalokowana, a rzeczywiście otrzymana od systemu to nie to samo. Nie wiem, jak to jest pod linuksem, ale windows daje pamięc dopiero wtedy, gdy program próbuje jej użyć, spróbujcie alokować tablicę rozmiaru gigabajta, następnie wcisnąć Ctrl+Alt+Esc (task manager) i zobaczyć zużycie pamięci: nie będzie tego wiele. Tylko potem nie odwołujcie się do ostatniego elementu ;)
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Stefan
pijak



Dołączył: 22 Lis 2005
Posty: 173
Przeczytał: 0 tematów


PostWysłany: Pon 15:12, 30 Paź 2006    Temat postu:

m^2 napisał:
To nie działa. Systemowy operator new zwraca kawałek pamięci rozmiaru co najmniej takiego, jak trzeba. Więc memSize będzie tylko ograniczeniem od dołu na używaną pamięć.

AFAIK new/malloc rezerwują dokładnie tyle, ile potrzeba na obiekt. Jeśli jest tak, jak mówisz, to pokaż przykład, gdzie new/malloc rezerwuje więcej niż sizeof(typ alokowany) - zaciekawiło mnie to, bo oznaczałoby to, że implementacja dołącza jakiś mechanizm zarządzania stertą, co wydaje mi się wielce nieprawdopodobne.
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
exeman
Mistrz grilla



Dołączył: 03 Lut 2006
Posty: 1603
Przeczytał: 0 tematów

Skąd: znienacka

PostWysłany: Pon 20:51, 30 Paź 2006    Temat postu:

Nie dam glowy, ale raczej sklonilbym sie do wersji m^2. W koncu malloc to jest jedna wielka kobyla. ;)
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
m^2
pijak



Dołączył: 15 Mar 2006
Posty: 62
Przeczytał: 0 tematów

Skąd: Katowice

PostWysłany: Pon 22:19, 30 Paź 2006    Temat postu:

CPP reference nic nie mówi na ten temat, ale np. Microsoft - owszem.
http://msdn2.microsoft.com/zh-cn/library/6ewkz86d.aspx napisał:
The malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information

Jeśli się nie mylę, pewna osoba z naszego roku miała przez to RTE w jednym zadaniu.


Ostatnio zmieniony przez m^2 dnia Wto 9:48, 31 Paź 2006, w całości zmieniany 1 raz
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Crow
alkoholik



Dołączył: 14 Mar 2006
Posty: 497
Przeczytał: 0 tematów

Skąd: KRK-NH

PostWysłany: Pon 22:23, 30 Paź 2006    Temat postu:

Z tego co slyszalem to ze wzgledow "optymalizacyjnych" wiele implementacji rezerwuje wiecej pamieci, a nastepnie "odcina" jej kawalki kazdemu wywolaniu operatora new czy tez malloc. Dzieki temu oszczedza sie na wywolaniach systemowych. Takie rozwiazanie jest chyba stosowane w stdlibc++ ale nie dam sobie glowy uciac.
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
m^2
pijak



Dołączył: 15 Mar 2006
Posty: 62
Przeczytał: 0 tematów

Skąd: Katowice

PostWysłany: Pon 22:57, 30 Paź 2006    Temat postu:

Poza tym system nie bawi się w przydzielanie pojedynczych bajtów - daje od razu całą stronę. W systemach 64 bitowych może to być ponad megabajt.
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Stefan
pijak



Dołączył: 22 Lis 2005
Posty: 173
Przeczytał: 0 tematów


PostWysłany: Pon 23:30, 30 Paź 2006    Temat postu:

m^2 napisał:
CPP reference nic nie mówi na ten temat, ale np. Microsoft - owszem.
http://msdn2.microsoft.com/zh-cn/library/6ewkz86d.aspx napisał:
The malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information

Jeśli się nie mylę, pewna osoba z naszego roku miała przez to RTE w jednym zadaniu.


Może się mylę, ale te uwagi raczej odnoszą się ogólnie do idei dynamicznej alokacji pamięci. Jeśli chodzi o pierwszy powód, to wynika on z faktu, że sizeof(A) dla struct A { char c; int i; }; wynosi zazwyczaj 8. Drugi, z faktu że free() jako argument przyjmuje tylko wskaźnik (podobnie jak delete[], który musi wywołać odpowiednią ilość destruktorów), zatem musi gdzieś zapamiętać rozmiar alokowanej pamięci.

Biorąc to pod uwagę, skłaniam się ku opini, że ww. kod jest raczej poprawny. Co chyba, że chcemy mieć sto procent pewności, co do rozmiaru zajmowanej pamięci, ale wtedy - jak pisał Exeman - najprawdopodobniej będzie to kosztem przenośności.
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
m^2
pijak



Dołączył: 15 Mar 2006
Posty: 62
Przeczytał: 0 tematów

Skąd: Katowice

PostWysłany: Wto 9:40, 31 Paź 2006    Temat postu:

1.Zwykle można sobie wybrać, do ilu zaokrąglany jest rozmiar klasy. Tak, jak powiedziałeś, najczęściej jest to 8 bajtów. Ale (tutaj: w systemach 64 bitowych)
http://msdn2.microsoft.com/en-us/library/ycsb6wwf.aspx napisał:
malloc is required to return memory on a 16-byte boundary.

2. Jest jeszcze 3 powód: w trybie debug Visual Studio malloc to _malloc_dbg, który alokuje trochę więcej.
http://msdn2.microsoft.com/zh-tw/library/faz3a37z.aspx napisał:
_malloc_dbg allocates the memory block with slightly more space than the requested size. The additional space is used by the debug heap manager to link the debug memory blocks and to provide the application with debug header information and overwrite buffers.

DODANE: 2Crow:
Swoją drogą, co rozumiesz przez stdlibc++? AFAIK standard nic nie mówi o tym, jak to implementować. Jeśli za kononiczną uważasz implementację gcc...to może zainteresuje Cię fakt, że od jakiegoś czasu gcc pod Windows używa microsoftowego malloca, importowanego z MSVCRT.DLL (nie czytałem changelogów, ale kiedyś na pewno było inaczej, bo ten dll nie występował w windowsie 95, w 98 - chyba już tak ).

DODANE:
Program, który dowodzi, że kod Stefana nie działa pod Windows:
Kod:
int main(){
    while(1){
        malloc(512);
        getchar();
    }
}

Użycie:
1. Skompilować, uruchomić.
2. Uruchomić manager zadań, zaznaczyć działający program.
3. Obserwując zużycie pamięci, wciskać enter.
Efekt: Co x (x zależy od ustawień systemu, w większość przypadków x ==8 ) uderzeń w enter system alokuje 512*x B. Wyjaśnienie dam za parę godzin, muszę jeszcze trochę poczytać ;)
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
exeman
Mistrz grilla



Dołączył: 03 Lut 2006
Posty: 1603
Przeczytał: 0 tematów

Skąd: znienacka

PostWysłany: Wto 13:54, 31 Paź 2006    Temat postu:

No bo alokuje blokami o czym wspomnial Crow.
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
m^2
pijak



Dołączył: 15 Mar 2006
Posty: 62
Przeczytał: 0 tematów

Skąd: Katowice

PostWysłany: Wto 15:01, 31 Paź 2006    Temat postu:

No bo alokuje stronami, o czym ja wspomniałem ;)
Crow mówił zapewne o tym samym, tylko, że jest to realizowane przez system, a nie przez malloca.
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
m^2
pijak



Dołączył: 15 Mar 2006
Posty: 62
Przeczytał: 0 tematów

Skąd: Katowice

PostWysłany: Wto 17:06, 31 Paź 2006    Temat postu:

Ok, przeczytałem na tyle dużo, że mogę powiedzieć coś konkretnego na ten temat.
Wszystko, co poniżej dotyczy 32 bitowego windowsa z jądem NT.

Pamięć jest zorganizowana w strukturę warstwową:

Memory Mapped File nie służy do alokacji pamięci, toteż nie czytałem, jak to działa ;)
Virtual Memory API - Pamięć jest podzielona na "strony", spójne kawałki pamięci wirtualnej o ustalonym rozmiarze, najmniejsze, jakie przydziela system. Dlaczego wirtualnej? Bo strona nie musi zmajdować się w pamięci, może być zrzucona na dysk. Na tym poziomie alokować i zwalniać (i robić kilka innych, czasami przydatnych rzeczy, pozwalających na pewne optymalizacje) tylko całe strony. Ich rozmiar jest stały dla procesu i ustalany przez system. Zależy od sprzętu, na maszynach x86 wynosi 4KB. Można zmienić rozmiar strony, trzeba jednak zejść do warstwy jądra i bawić się hardwarem. [link widoczny dla zalogowanych] jest narzędziem, które robi coś takiego, na windowsach XP64 / XP SP2 / 2003 / Vista zwiększa rozmiar strony do 4 MB. (Na starszych systemach nie da się więcej niż 3MB, 7-max daje 2). Po co? Im mniej stron tym mniej pracy na ich tworzenie, pilnowanie statusu, utrzymywanie, rozważania zrzucić na dysk czy zostawić itp. Wg autora (Igor Pavlov, ten sam, który napisał 777 i 7-zipa) dla niektórych aplikacji daje to 10-20% zysk wydajności. Strata: większe zużycie pamięci.
Heap Memory API, jak nazwa wskazuje, operuje na stertach. Tak, może ich być więcej. Każdy proces ma domyślnie swoją stertę, może tworzyć nowe. Sterty są bardziej elastyczne w alokacji pamięci - tutaj wszystko jest zaokrąglane wzwyż do 16 bajtów. Jednakże pojawia się dodatkowy narzut - każda alokacja to dodatkowe 16 bajtów w tablicy zapamiętującej kto, gdzie i ile. Czyli alokacja jednego bajtu to (patrząc na tym poziomie) strata 31 bajtów. A tak naprawde - wszystko i tak jest zaokrąglane do końca strony, jednak wiele małych i niezbyt okrągłych (16n+1) alokacji jest strasznym marnowaniem pamięci.
Tworzenie nowych kopców - widzę jedną sytuację, kiedy ma to sens - w aplikacjach wielowątkowych HeapManager musi zapewniać dostęp symultaniczny, domyślny stos to robi. W wielu sytuacjach można dla każdego wątku stworzyć osobny stos bez tej funkcjonalności - będzie działał trochę szybciej.
Local, Global Memory API - Alokacja lokalna i globalna to... to samo. Zaszłość jeszcze z windowsa 1.0, tam alokacja lokalna oznaczała alokację ze sterty procesu, a globalna - z systemu. Ponieważ w NT nie daje to żadnego zysku, a aplikacja i tak nie potrafi rozróżnić, jaką pamięć dostała - wszystko idzie ze sterty procesu. Od HeapAlloca różnią się jedną opcją - pamięć może być alokowana jako FIXED lub MOVABLE. W pierwszym przypadku działa jak HeapAlloc, w drugim zwraca nie wskaźnik, lecz uchwyt. Pamięć MOVABLE, jak nazwa wskazuje może być przesuwana, gdy system uzna to za wygodne, więc trzeba ją zablokować przed użyciem. Tutaj jest (był?) bug - LockCount nie może przekroczyć 256 (tak wynika z atrykułu na MSDN, jednakże chyba miało być 255, bo jest jeszcze 0). Jądro NT i tak nie przesuwa pamięci, więc użycie MOVABLE to tylko utrudnianie sobie życia.
CRT Memory Functions - czyli malloc i free. Na tym schemacie są ponad Heap Memory API, jednakże jest to kwestia implementacji. Nikt nie broni pisania malloca działającego bezpośrednio na stronach.
Czego używać?
Kiedyś znalazłem w sieci benchmark, z którego wynika:
Najszybszy jest VirtualAlloc.
5% wolniejsze- HeapAlloc i GlobalAlloc
malloc działa 20% dłużej.
Ale przecież malloc to nie jest konkretna funkcja, zależy, jaką kto napisze, np.
Kod:
//==========================================
// LIBCTINY - Matt Pietrek 2001
// MSDN Magazine, January 2001
//==========================================
#include <windows.h>
#include <malloc.h>

extern "C" void * __cdecl malloc(size_t size)
{
    return HeapAlloc( GetProcessHeap(), 0, size );
}

extern "C" void __cdecl free(void * p)
{
    HeapFree( GetProcessHeap(), 0, p );
}
nie będzie aż tyle wolniejsze od HeapAlloca. Jeśli GetProcessHeap wykona się tylko raz i wynik zapamięta - będzie jeszcze szybciej. inline będzie równie dobre, jak HeapAlloc.
Wyniki nie są zaskakujące - każdy wywołuje poprzedni i coś robi z tym, co otrzyma.
Więc co jest najlepsze? To zależy.
-Jeśli program ma działać ni tylko pod windows - kwestia oczywista. W ekstremalnych sytuacjach można się pokusić o własną implementację malloca, która będzie dołączana tylko pod windows, gdzie indziej - używać innej (innych? 8) )
-Kiedy piszemy tylko pod windows, ale szybkość alokacji nie jest kluczowa (99% przypadków..) - także używałbym malloca. Może kiedyś przyjdzie przerabiać program lub chociaż jego część na inny system, użycie standardowych funkcji jest bardziej czytelne dla programistów, którzy nie znają Windows.
-Kiedy szybkość jest ważna - własna implementacja malloca, w 95% przypadków oparta na HeapAlloc, bo tak jest prościej. IMO tylko sporadycznie (gra komputerowa, kompresja plików itp.) może się opłacić użycie wirtualnej alokacji.

DODANE: Właściwie to trochę zboczyłem z tematu..ale powyższą wypowiedź można interpretować: "Pod Windows NT ilość dynamicznie alokowanej pamięci można sprawdzić tylko zliczając ilość stron, a to zrobić - tylko używając funkcji systemowych, więc nie istnieje metoda niezależna od platformy, powalająca na sprawdzenie czegoś takiego"


Ostatnio zmieniony przez m^2 dnia Wto 19:05, 31 Paź 2006, w całości zmieniany 1 raz
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Crow
alkoholik



Dołączył: 14 Mar 2006
Posty: 497
Przeczytał: 0 tematów

Skąd: KRK-NH

PostWysłany: Wto 17:28, 31 Paź 2006    Temat postu:

@m^2: stdlibc++ nie oznacza "Standardu C++" tylko biblioteke z ktorej linuxowy gcc importuje funkcje. Myslalem ze to jasne. :]
Powrót do góry
Zobacz profil autora
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Stefan
pijak



Dołączył: 22 Lis 2005
Posty: 173
Przeczytał: 0 tematów


PostWysłany: Śro 16:40, 01 Lis 2006    Temat postu:

Big thx Maciek!
Powrót do góry
Zobacz profil autora
Wyświetl posty z ostatnich:   
Napisz nowy temat   Odpowiedz do tematu    Forum Informatyka UJ forum Strona Główna -> Informatyka Wszystkie czasy w strefie EET (Europa)
Strona 1 z 1

 
Skocz do:  
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach

fora.pl - załóż własne forum dyskusyjne za darmo
Powered by phpBB © 2001, 2005 phpBB Group
Regulamin