Heap management

Giorgos Keramidas keramida at ceid.upatras.gr
Fri Jun 2 23:14:15 EEST 2006


On 2006-06-02 21:21, Apostolos Manolitzas <apostolix at gmail.com> wrote:
> Καλησπέρα σε όλους,
>
> παρατηρώ το εξής φαινόμενο σε ένα σύστημα που τρέχει kernel 2.4.12
> Έχω μια σερβερ εφαρμογή που δέχεται commands από sockets οπότε με τα
> commands αυτά γίνονται αρκετά new() της τάξης των 10^6 αλλά με μεγέθη
> των Objects αρκετά μικρά 10-100 bytes.
> Στην συνέχεια έρχονται οι αντίστοιχες εντολές για την απομάκρυνση
> αυτών των objects με τα αντίστοιχα delete. Έχω μετρήσει το πλήθος των
> new και ειναι το ίδιο με αυτό των delete δηλαδή ξέρω σίγουρα οτι δεν
> έχω Leak, ή αν έχω δεν το βρίσκω ή είναι πολύ μικρό.
>
> Το πρόβλημα μου είναι το εξής στην αρχή το πρόγραμμα έχει μέγεθος 3Μ
> όταν κάνω όλα τα new το μέγεθος εκτοξεύεται στα 27Μ που το θεωρώ
> φυσιολογικό γιατί μετράω όλα τα new και είναι πάρα πολλά. Το μεγάλο
> μου ερώτημα είναι γιατί όταν κάνω τα αντίστοιχα delete δεν πέφτει πάλι
> στα 3Μ! ή έστω εκεί κοντά. Δηλαδή η μνήμη διατηρείται στα 25Μ και όταν
> εφαρμόσω πάλι την ίδια ακολουθία εντολών (new - delete) η μνήμη
> ανεβαίνει στα 30Μ.
>
> Διάβασα για πιθανόν caching που κάνει η μνήμη, οπότε φτιάχνω ένα
> προγραμματάκι που κάνει malloc όση ελεύθερη έχει απομείνει ώστε να το
> στρεσάρω όσο μπορώ, μπας και την δώσει την άτιμη. Το αποτέλεσμα είναι
> οτι δεν την δίνει αυτή την μνήμη.
>
> Χρησιμοποιώ το top & ps για τα συμπεράσματα καθώς και την δομή
> mallinfo()[1] για πιο ακριβή συμπεράσματα. Επίσης χρησιμοποίησα και το
> nmap και είδα οτι όλη αυτή η μνήμη που δεσμεύεται είναι στο heap.
>
> Ξέρεις κανείς πώς εξηγείται αυτό το φαινόμενο ή έστω που να κοιτάξω
> για να το καταλάβω;

Ναι, υπάρχει πολύ λογική εξήγηση.  Οταν κάνεις free(), οι περισσότεροι
memory allocators δεν επιστρέφουν αμέσως τη μνήμη στο λειτουργικό
σύστημα, για διάφορους λόγους.

Όσο γι αυτό ...

[1] http://www.gnu.org/software/libc/manual/html_node/Statistics-of-Malloc.html

αυτό είναι GNU malloc-specific.  Σε άλλες malloc() υλοποιήσεις είτε δεν
υπάρχει τέτοια υποστήριξη, είτε είναι διαφορετικής μορφής.

Επίσης:

> Το πρόβλημα μου είναι το εξής στην αρχή το πρόγραμμα έχει μέγεθος 3Μ
> όταν κάνω όλα τα new το μέγεθος εκτοξεύεται στα 27Μ που το θεωρώ
> φυσιολογικό γιατί μετράω όλα τα new και είναι πάρα πολλά. Το μεγάλο
> μου ερώτημα είναι γιατί όταν κάνω τα αντίστοιχα delete δεν πέφτει πάλι
> στα 3Μ!

Μόνο σε πολύ απλοϊκούς, custom allocators μπορεί να δεις κάτι τέτοιο, ή
σε allocators που είναι φτιαγμένοι για ειδικά περιβάλλοντα
(π.χ. embedded εφαρμογές) -- εκεί όπου το να έχει over-allocation ένα
πρόγραμμα μπορεί να καθυστερήσει ή ακόμα και να δημιουργήσει σοβαρά
προβλήματα σε άλλες εφαρμογές του ίδιου συστήματος.

> Δηλαδή η μνήμη διατηρείται στα 25Μ και όταν εφαρμόσω πάλι την ίδια
> ακολουθία εντολών (new - delete) η μνήμη ανεβαίνει στα 30Μ.

Για να καταλάβεις ακριβώς που πάνε αυτά τα έξτρα 5 MB θα πρέπει να
διαβάσεις τις τεχνικές λεπτομέρειες της υλοποίησης της GNU malloc().
Είναι πολύ πιθανόν, όταν κάνεις τόσα πολλά μικρά allocations, το
overhead από τα malloc metadata που χρησιμοποιεί εσωτερικά ο allocator
να είναι σημαντικό σε μέγεθος.  Το γεγονός ότι αυτά τα metadata (καθώς
και τα cached allocations τα οποία περιγράφουν) δεν έχουν ελευθερωθεί
ακόμα δεν είναι περίεργο.  Αν σε ενοχλεί, βέβαια, μπορείς να παίξεις με
τα tunables της GNU malloc(), όπως:

        /* Το παρακάτω είναι GNU extension και δεν παίζει σε άλλες
         * malloc() υλοποιήσεις.
         */
        (void) mallopt(M_TRIM_THRESHOLD, 1);

Δε στο προτείνω σαν 'λύση', εκτός κι αν έχεις το χρόνο και τη διάθεση να
μετρήσεις πραγματικά αν αυτό είναι καλύτερο ή χειρότερο από την
προκαθορισμένη συμπεριφορά της GNU malloc().

- Γιώργος




More information about the Linux-greek-users mailing list