2010-11-04 13 views
11

Mam program, który intensywnie używa std::map. W systemie Windows dużo więcej pamięci jest używane pod Linuksem. Czy ktoś ma pomysł, dlaczego tak się dzieje?wykorzystanie pamięci struktur danych STL, Windows vs. linux

Linux: Last process took 42.31 s and used not more than 909 MB (RSS 900 MB) of memory

Windows: Last process took 75.373 s and used not more than 1394 MB (RSS 1395 MB) of memory

Używam gcc 4.4.3 oraz kompilator C++ w wierszu polecenia VS 2010, z ustawieniami uwalnianiu.

EDIT: Niestety za odpowiedzi na pytania, które późno ...

Kod wygląda następująco:

enum Symbol { 
    ... 
} 

class GraphEntry { 

    public: 

    ... 

    virtual void setAttribute (Symbol name, Value * value) = 0; 

    const Value * attribute (Symbol name) const; 

    private: 

    std::map<Symbol, Attribute> m_attributes; 
}; 

class Attribute { 

    public: 

    Attribute (Symbol name, Value * val); 

    ... 

    Symbol name() const; 

    Value * valuePointer() const; 

    void setValuePointer (Value * p); 

    private: 

    Symbol m_name; 

    Value * m_value; 
}; 

class Graph : public GraphEntry { 

    ... 

    public: 

    Node * newNode (...); 

    Graph * newSubGraph (...); 

    Edge * newEdge (...); 

    ... 

    setSomeAttribute (int x); 

    setSomeOtherAttribute (float f); 

    ... 

    private: 

    std::vector<GraphEntry *> m_entries; 
}; 

Całość opisuje strukturę wykres, który może pomieścić kilka atrybutów jego węzłów i krawędzie. Value to tylko klasa podstawowa, a pochodne klasy mogą zawierać wartości z dowolnymi typami, takimi jak int lub std::string.

EDIT 2: Pod Windows, używam następujące flagi: -DRELEASE -DNDEBUG -DQT_NO_DEBUG -DQT_NO_DEBUG_OUTPUT -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DNOMINMAX /O2 /MD /Gy /EHsc

EDIT 3: Wykorzystanie pamięci są odczytywane z pliku/proc pod Linux (jak memuse). W systemie Windows niektóre funkcje WinAPI są wywoływane, ale nie jestem ekspertem w tej dziedzinie, więc to wszystko, co mogę o tym powiedzieć.

EDIT 4: Korzystanie /GS- i -D_SECURE_SCL wyników w Last process took 170.281 s and used not more than 1391 MB (RSS 1393 MB) of memory

+0

Czy używasz programu Visual Studio? Jeśli tak, to która wersja? Czy jesteś w debugowaniu? – msandiford

+1

W jaki sposób zmierzyłeś zużycie pamięci? – camh

+8

Kod lub to się nie stało. – Puppy

Odpowiedz

8

Można zauważyć, że użycie pamięci w systemie Windows jest od 1 do 2 razy większe. Odkładając na bok algorytmy, Windows malloc(), a następnie wszelkie struktury danych przydzielone do sterty za pośrednictwem new (takie jak węzły std::map z domyślnym typem przydziału) są wyrównane do 16 bajtów. W systemie Linux: glibc defaults to 8 byte alignment. Zakładając pewne wygładzenie różnic w wyniku fragmentacji, optymalizację zbioru nieużywanych stron itp. Można się spodziewać, że różnice staną się mniej widoczne.

Szybkie sprawdzenie kodu wskazuje klucz mapy, a typy wartości powinny wynosić odpowiednio 4 i 8 bajtów (i Attribute). Zaokrąglają do 8 bajtów w systemie Linux i 16 bajtów w systemie Windows. Powinieneś mieć taką samą liczbę węzłów map, przynajmniej w implementacji MSVC, starają się pochłonąć co najmniej 22 bajty, które MSVC rozszerzy do 32 ze względu na reguły dopasowania członków, co jest również jego ziarnistością malloc. GCC rozszerzy go do 24, co oznacza około 48 bajtów w MSVC do GCC/Linux "32 na węzeł. Mniej więcej 50% więcej pamięci w systemie Windows.

Oto struktura węzeł stosowany w MSVC, mogę spojrzeć w górę równowartość GCC jeśli jesteś zainteresowany:

struct _Node 
    { // tree node 
    _Nodeptr _Left; // left subtree, or smallest element if head 
    _Nodeptr _Parent; // parent, or root of tree if head 
    _Nodeptr _Right; // right subtree, or largest element if head 
    value_type _Myval; // the stored value, unused if head 
    char _Color; // _Red or _Black, _Black if head 
    char _Isnil; // true only if head (also nil) node 

dodam dla tych, którzy są zaznajomieni z jak działa zużycie pamięci, istnieje kilka czynników, przy odtwarzaniu:

  • Pamięć jest przydzielana w porcjach zaokrąglania do następnej wielokrotności linii trasowania dla zastosowanego mechanizmu alokacji. W przypadku sterty używane są reguły wyrównania malloc() (chyba że podważysz zwykłą stertę lub użyjesz innej alokacji niż domyślna).
  • Pamięć wirtualna jest "dostarczana" przez system w porcjach zwanych stronami, wielokrotnościami całkowitymi rozmiaru ramki, co wykracza poza zakres tego pytania. Ma to niewielki wpływ na odpowiedź, ponieważ wykorzystanie pamięci jest tak ogromne w porównaniu z rozmiarem strony (4K), a rozmiar strony z kolei jest tak ogromny w porównaniu do dopasowań w użyciu (8 i 16).
+0

Powinienem dodać zwiększony czas działania w systemie Windows to połączenie zwiększonego rozmiaru struktur, co oznacza, że ​​może wystąpić mniejsze buforowanie, oraz różnice w optymalizacji instrukcji w używanych kompilatorach. –

+0

Dzięki za odpowiedź. Zwiększone środowisko uruchomieniowe jest również spowodowane wolniejszą maszyną używaną do tworzenia okien. – swegi

0

Czy wykonać test w trybie debugowania zwolnienia lub pod oknami? STL w trybie debugowania wykonuje wiele dodatkowych sprawdzeń; może też zużywa więcej pamięci, aby wykonać wszystkie kontrole.

+0

Używam trybu zwolnienia – swegi

0

Dla VC++ spróbuj użyć/GS-command switch linii.

6

Niektóre wersje VC++ używają sprawdzonych iteratorów (_SECURE_SCL) również w kompilacjach wydań. VC2005 i VC2008 mają je domyślnie włączone. VC2010 wyłącza je by default

W zależności od kompilatora może to być kolejna rzecz do sprawdzenia (i wyłączenia).

+1

+1. Rozwiązało to dla mnie, gdy zostałem wezwany do rozwiązania problemu. – Sjoerd

+1

@swegi: proszę skomentuj, czy to dotyczy ciebie, a jeśli tak, to jak porównanie porównało później ... –

7

Każdy kompilator jest dostarczany z własnej realizacji STL, dlatego porównujesz:

  • GCC STL + Linux procedur alokacji
  • VC++ STL + Windows procedury przydziału

to całkiem Trudno jest przeprowadzić tutaj sensowne porównanie, ponieważ nie wiadomo, która z procedur rutynowych lub implementacja STL (lub ewentualnie obie) jest rzeczywiście odpowiedzialna.

Przypuszczam, że nie porównujesz programu 32-bitowego z programem 64-bitowym, ponieważ byłoby to jeszcze mniej znaczące.

+0

Oba systemy są 32-bitowe. – swegi

0

Kiedy mówisz, że używana pamięć jest "nie większa niż", czy odwołujesz się do użycia pamięci szczytowej lub średniego zużycia pamięci podczas okresu użytkowania aplikacji?

Upewnij się, że pamięć przydzielona przez aplikację za pomocą "nowego" lub "malloc" lub innego wywołania biblioteki alokacji pamięci jest zwalniana z powrotem za pomocą "usuń" lub "bezpłatnie" lub inne równoważne wywołanie biblioteki.

W systemie Linux można użyć valgrind i sprawdzić, czy nie ma wycieków pamięci.

+0

Wykorzystanie pamięci szczytowej – swegi

Powiązane problemy