[C++] delete nie zwalnia pamieci

Problemy dotyczące programowania.

Moderatorzy: Moderatorzy, Administratorzy

Awatar użytkownika
roanoke
Użytkownik
Posty: 71
Rejestracja: 2006-07-22, 09:31

[C++] delete nie zwalnia pamieci

Post autor: roanoke »

Witam

Stworzyłem typ Tablica, w main() tworzę tablicę typu Tablica dynamicznie.
przy zwalnianiu pamięci za pomocą delete dzieją się dziwne rzeczy, sprawdzam w menedżerze procesów czy zwalnia.

kiedy źle zwalnia to jest:
np. startuje z 100kB, new podbija do 40 MB, a po delete jest 33,6 MB,
a jak dobrze to wtedy po delete wraca do ~100kB

DOBRZE zwalnia kiedy:
+ np. kiedy utworze sobie dynamicznie jeszcze jakiś osobny typ Tablica i go zwolnię, to przy tym zwalnianiu zaczyna działać ten delete mojej tablicy Tablic
+ kiedy RozmiarTablicy(z main) > 100 000 to delete zwalnia poprawnie pamięć, IloscTablic nie ma znaczenia
+ kiedy w pętli w której tworzę w tablicy elementy typu Tablica, zaraz po utworzeniu 'Ptr = new Tablica(RozmiarTablicy)' robię 'delete Ptr'

ŹLE zwalnia
- ale kiedy już robię 'delete Ptr' w osobnej pętli to nie działa

a właśnie najpotrzebniejsze jest to wyżej co ŹLE działa.
zrobiłem sobie trochę komunikatów w programie do logowania, i za każdym razem jak wywołuje mi destruktor to wskaźnik, który usuwa == wskaźnikowi utworzonemu przez konstruktor, także to jest ok. i żadnych błędów przy kompilacji ani uruchamianiu.

Kod: Zaznacz cały

class Tablica {
  public:
    Tablica() {
      _RozmiarTablicy = 0;
      _PTab = NULL;
    }
    Tablica(unsigned long int Rozmiar) {
      _RozmiarTablicy = Rozmiar;
      _PTab = TworzTablice(_RozmiarTablicy);
    }
    ~Tablica() {
      delete [] _PTab;
      _PTab = NULL;
    }
    int* TworzTablice(unsigned long int Rozmiar) {
      int *PTmp = new int[Rozmiar];
      return PTmp;
    }

  private:
    int *_PTab;
    unsigned long int _RozmiarTablicy;
}; //-----------------------

int main() {
  Tablica **Ptr = NULL;
  unsigned long int IloscTablic = 10;
  //dopiero przy RozmiarTablicy > 100 000 zwalnia pamiec
  unsigned long int RozmiarTablicy = 100000;

  getchar();
  Ptr = new Tablica *[IloscTablic];
  for(unsigned long int i = 0; i < IloscTablic; i++) {
    Ptr[i] = new Tablica(RozmiarTablicy);
    //jak zwalniam w petli od razu to dziala
    //delete Ptr[i];
    //Ptr[i] = NULL;
  }
  getchar();
  //to nie chce dzialac kiedy RozmiarTablicy < 100 000
  for(unsigned long int i = 0; i < IloscTablic; i++) {
    delete Ptr[i];
    Ptr[i] = NULL;
  }
  delete [] Ptr;
  Ptr = NULL;

  getchar();
}
Miał ktoś podobne doświadczenia?

//edit może muszę własne new i delete zrobić ?? może mi ktoś napisać jaki ma sens tworzenie własnych new i delete (z malloc i free w środku) ?
Ostatnio zmieniony 2009-03-21, 23:10 przez roanoke, łącznie zmieniany 2 razy.
acek
Użytkownik
Posty: 47
Rejestracja: 2006-09-26, 21:27
Kontakt:

Re: [C++] delete nie zwalnia pamieci

Post autor: acek »

To, co obserwujesz wynika z dzialania sbrk(2) i brk(2) dla malych obiektow oraz mmap(2) i munmap(2) dla duzych obiektow.
roanoke pisze:

Kod: Zaznacz cały

  unsigned long int IloscTablic = 10;
LiczbaTablic.
Awatar użytkownika
roanoke
Użytkownik
Posty: 71
Rejestracja: 2006-07-22, 09:31

Re: [C++] delete nie zwalnia pamieci

Post autor: roanoke »

hmmm...
tylko, że właśnie zależy to od RozmiarTablicy.
dla konfiguracji RozmiarTablicy = 100, IloscTablic = 100 000 nie zwalnia, a dla RozmiarTablicy = 100 000, IloscTablic = 100 zwalnia, IloscTablic nie ma znaczenia
Ostatnio zmieniony 2009-03-22, 00:24 przez roanoke, łącznie zmieniany 1 raz.
acek
Użytkownik
Posty: 47
Rejestracja: 2006-09-26, 21:27
Kontakt:

Re: [C++] delete nie zwalnia pamieci

Post autor: acek »

roanoke pisze:hmmm...
tylko, że właśnie zależy to od RozmiarTablicy.
Tak powinno byc. Przeczytales manuala sbrk(2) i brk(2)? Proponuje

Kod: Zaznacz cały

info libc Memory
.
Awatar użytkownika
roanoke
Użytkownik
Posty: 71
Rejestracja: 2006-07-22, 09:31

Re: [C++] delete nie zwalnia pamieci

Post autor: roanoke »

dzięki, znalazłem odpowiedź, teraz tylko rozwiązanie trzeba znaleźć. chociaż niżej jakieś rozwiązania są podane, w sumie logicznie wytłumaczone

http://ubuntuforums.org/archive/index.php/t-305441.html
The classical way of doing memory allocation in Unix is to find out where the limit of available space is, and then tell the system to raise it by the amount you want (the system calls are called brk and sbrk). The memory allocation functions of the language you're using do this and then create an appropriate structure (list, array or whatever) and sends it to you.

To give back memory to the system would be by lowering the limit again, with the same system calls. In practice, this is never done, because of two reasons:

1) Usually, a number of allocation calls are been made from the user's code, some structures freed again, etc. so that you might give back a big block if it wasn't for one chunk in the middle of it that's still used, and the added complexity of keeping track of when you can lower the limit isn't worth it;

2) It's unusual for a program to at an early point allocate a lot of memory, and later use only a tiny portion, so it makes sense to assume that if memory is freed by your program, it will be worth keeping the allocated memory around to reuse later. The rare exceptions exist, of course.

3) Even when the memory was given back to the system by brk/sbrk, it wouldn't actually be made available to other programs. Only the bookkeeping value of where the limit is would be changed. I don't know if this is the case in Linux, but it used to be in most older Unix systems.


A more modern way of allocation could make use of the system call mmap, which doesn't require the new block of memory to be adjacent to any old one. I don't know how much it is used in modern allocators.

If your application is not just a test program, but one of the exceptions to my point 2, maybe you can: A) do whatever calculation it is that takes so much space in a separate process and write its result to a file, then exit it and start the other small process to do the remaining calculation; B) Forget the problem - 16M is not that much, and if the memory really isn't used, it will be paged out so it won't bother other processes, unless swap memory is really low; C) Scenario A, but let the processes communicate in real time, and restart the first process whenever it gets too large.
acek
Użytkownik
Posty: 47
Rejestracja: 2006-09-26, 21:27
Kontakt:

Re: [C++] delete nie zwalnia pamieci

Post autor: acek »

Tuning alokatora pamieci (i nie tylko) w glibc jest mozliwy przez przekazywanie wartosci w zmiennych srodowiskowych, np. MALLOC_MMAP_THRESHOLD_. Jest tez funkcja mallopt. Nie nalezy lekkomyslnie nadawac wartosci tym zmiennym.
Podpowiedz: najmniejszy mozliwy rozmiar strony pamieci w architekturze i386 to 4096 bajtow.
ODPOWIEDZ