Δέσμευση Μνήμης (memory allocatio) Τι σημαίνει; Διαχείριση Μνήµης Ο καλός προγραμματισμός επιβάλλει την αποδοτική χρήση της μνήμης του Η/Υ. Είναι σημαντικό να καταλαβαίνουμε τις διαδικασίες δέσμευσης μνήμης: Για την αποδοτική δέσμευση δομών δεδομένων μη προκαθορισμένου μεγέθους. Για την αποφυγή «διαρροών μνήμης» (memory leaks). Για την επίδοση του εκτελούμενου προγράμματος (ru-time performace). 1 2 Μνήμη προγραμμάτων Ιεραρχία μνήμης Χώρος αποθήκευσης μεταβλητών, δεδομένων, κώδικα, κλπ. Το UNIX παρέχει στις διεργασίες μας έναν εικονικό χώρο διευθύνσεων (virtual address space). 3 4 Σχεδιάγραμμα της μνήμης μιας διεργασίας Σχεδιάγραμμα μνήμης διεργασιών Text: δυαδικός (ιθαγενής / τελικός) κώδικας προγράμματος της διεργασίας. : σταθερές προγράμματος. (Block Started by Symbol (): γενικές και στατικές μεταβλητές (most moder assemblers produce a sectio i their output object module cotaiig all reserved uiitialized space). Heap: δυναμική μνήμη. Stack: στοίβα, τοπικές μεταβλητές. Στην Γ/Π C: it isize; char *f(void) char *p; isize = 8; p = malloc(isize); ß ß stack ß data ß heap retur p; 5 6
Δέσμευση Μνήμης Οι γενικές και οι στατικές μεταβλητές κατά την αρχικοποίηση του προγράμματος. Οι τοπικές μεταβλητές κατά την κλήση μιας υπορουτίνας/μεθόδου. Η δυναμική μνήμη με τη χρήση της malloc (στη C) και με τη δημιουργία νέων αντικειμένων (JAVA). Αποδέσμευση Μνήμης Γενικές και στατικές μεταβλητές με τη λήξη ενός προγράμματος. Τοπικές μεταβλητές με την επιστροφή από μια υπορουτίνα/ μέθοδο. Δυναμική μνήμη με χρήση της free (στη C) και από τον αποκομιστή σκυβάλων (garbage collector) στη JAVA. Όλη η μνήμη αποδεσμεύεται με τη λήξη του προγράμματος. 7 8 Αποθηκευτικοί Χώροι Αποθηκευτικοί Χώροι Καταχωρητές (Registers): Μέσα στον επεξεργαστή Γρήγορη πρόσβαση Μικρός αριθμός Διαφανείς προς τον προγραμματιστή Στοίβα (Stack): Τοποθετείται στον εικονικό χώρο διευθύνσεων μνήμης (RAM) Απευθείας πρόσβαση από τον επεξεργαστή μέσω του Δείκτη Στοίβας (Stack Poiter) Χρησιμοποιείται για δεδομένα για τα οποία ο μεταφραστής-java μπορεί να γνωρίζει ακριβές μέγεθος και χρόνο ζωής (ώστε να διαχειρίζεται κατάλληλα τον Δ/Σ). Πολύ γρήγορη και αποδοτική πρόσβαση. Αποθηκεύει εγγραφήματα δραστηριοποίησης (activatio records ή stack frames). Περιορισμένης λειτουργικότητας, γι αυτό και χρησιμοποιείται κυρίως για την αποθήκευση ορισμένων μόνο δεδομένων και κυρίως χειριστήριων αντικειμένων. 9 Σωρός (heap): Τοποθετείται στον εικονικό χώρο διευθύνσεων μνήμης (RAM) Μνήμη Γενικής χρήσης, όπου «διαβιούν» όλα τα αντικείμενα της JAVA Πιό ευέλικτος από την στοίβα: ο μεταφραστής δεν χρειάζεται να γνωρίζει εκ των προτέρων πόση μνήμη να δεσμεύσει στον σωρό για την αποθήκευση αντικειμένων, ή τον χρόνο ζωής των καταχωρούμενων αντικειμένων. Όποτε χρειαστεί να δημιουργηθεί ένα αντικείμενο, πρέπει να γραφτεί ο σχετικός κώδικας για την δημιουργία του και να κληθεί με την χρήση της ew. Τότε γίνεται η δέσμευση της μνήμης και εκτελείται ο κώδικας αρχικοποίησης. Πιό αργή η καταχώρηση και πρόσβαση απ ότι στην στοίβα. 10 Η αποθήκευση των δεδομένων Στατική Αποθήκευση (static storage) Η στατική αποθήκευση υποδηλώνει την αποθήκευση δεδομένων σε συγκεκριμένη-αμετάβλητη θέση (fixed locatio). Η πραγματική αποθήκευση στατικών δεδομένων γίνεται στη RAM. Περιέχει δεδομένα τα οποία είναι διαθέσιμα για όλη την διάρκεια εκτέλεσης του προγράμματος. Η λέξη-κλειδί static μπορεί να χρησιμοποιηθεί για τον προσδιορισμό κάποιου στοιχείου μιας κλάσης ως στατικού. Τα αντικείμενα στην JAVA δεν τοποθετούνται ποτέ στην στατική μνήμη. Σταθερή Μνήμη (costat storage) Αντιστοιχεί στις σταθερές τιμές που χρησιμοποιούνται στον κώδικα. 11 Αποθήκευση εκτός RAM Αφορά σε δεδομένα τα οποία «διαβιούν» τελείως εκτός του προγράμματος, ενώ το πρόγραμμα δεν τρέχει. Εκτός ελέγχου από το πρόγραμμα. Υπάρχουν δύο βασικά παραδείγματα: Streamed objects: αντικείμενα που μετατρέπονται σε ροή χαρακτήρων (byte stream) συνήθως για να σταλούν σε μιάν άλλη μηχανή. Persistet objects: αντικείμενα που τοποθετούνται στον δίσκο ώστε να διατηρήσουν την κατάστασή τους όταν το πρόγραμμα τελειώσει. Βασικό χαρακτηριστικό αυτών των αντικειμένων είναι ότι μπορούν να «μετατραπούν» σε κανονικά αντικείμενα στη RAM, μόλις αυτό χρειασθεί. 12
Αντικείμενα στη JAVA Τα δεδομένα στην JAVA κωδικοποιούνται σαν αντικείμενα. Για κάθε αντικείμενο πρέπει να υπάρχει ένα χειριστήριο (hadle) μέσω του οποίου αποκτούμε πρόσβαση στο ίδιο το αντικείμενο και το διαχειριζόμαστε (τις μεθόδους του, τα δεδομένα του). Π.χ. Strig s; // δημιουργία χειριστηρίου Δημιουργία αντικειμένων Μετά την δημιουργία-δήλωση ενός χειριστηρίου, πρέπει να γίνει η διασύνδεσή του με κάποιο νέο αντικείμενο. Η δημιουργία ενός νέου αντικειμένου γίνεται με τη χρήση της εντολής ew: Strig s = ew Strig( asdf ); // Strig είναι ειδική περίπτωση τύπου Strig s = asdf ; Strig s = ew Strig( asdf ); // αρχικοποίηση αντικειμένου BakAcct b1 = ew BakAcct(21338, 0.0); 13 14 Αρχέγονοι Τύποι-primitive types Η δημιουργία αντικειμένων με την ew έχει κόστος, λόγω της αποθήκευσης στον σωρό και ό,τι αυτή συνεπάγεται. Για απλούς-αρχέγονους τύπους δεδομένων, η JAVA ξεφεύγει από τον μοντέλο των αντικειμένων και ακολουθεί την προσέγγιση της C και της C++. Έτσι, με την δήλωση μιας τοπικής μεταβλητής ως έχουσας αρχέγονο τύπο, δημιουργείται αυτόματα χώρος για την μεταβλητή αυτή - χωρίς χρήση της ew - και η μεταβλητή τοποθετείται στην στοίβα. Τι γίνεται για πεδία δεδομένων αρχέγονων τύπων; Ο ακριβής χώρος που κρατιέται για μεταβλητές αρχέγονων τύπων καθορίζεται από τον μεταφραστή της JAVA. Υπάρχουν ωστόσο και κλάσεις-συσκευαστές (wrapper classes) για τους αρχέγονους τύπους: char c = x ; Character C = ew Character( x ); 15 16 Πεδίο ισχύος - Εμβέλεια (scopig) Πεδίο ισχύος μεταβλητών (scopig). Μια μεταβλητή που ορίζεται μέσα σε κάποιο πεδίο, είναι υπαρκτή μέχρι το τέλος του πεδίου αυτού. it x = 12; it q = 96; Read-oly object Σε αντίθεση με την C και την C++, το ακόλουθο είναι συντακτικό σφάλμα: it x = 12; it x = 96; 17 18
Διάρκεια ζωής αντικειμένων Δημιουργία νέων τύπων: κλάσεις Ένα αντικείμενο που δημιουργείται με χρήση του ew διατηρείται ακόμη και μετά το τέλος του σχετικού πεδίου εμβέλειας (scope). Το αντίστοιχο, ωστόσο, χειριστήριο, εξαφανίζεται: Strig s = ew Strig( a strig ); /* ed of scope */ Ο τύπος των αντικειμένων στην JAVA καθορίζεται με τον ορισμό κλάσεων: class ATypeName /* class body */ Αντικείμενα μιας κλάσης δημιουργούνται με χρήση της ew: ATypeName a = ew ATypeName(); Στον ορισμό των κλάσεων συμπεριλαμβάνονται: Πεδία δεδομένων (fields): Αντικείμενα οποιουδήποτε τύπου, που αντιπροσωπεύονται από κάποια χειριστήρια. Χρήζουν αρχικοποίησης με την ew. Mεταβλητές αρχέγονων τύπων. Αποκομιστής σκυβάλων (garbage collector) Ο προγραµµατιστής δεν καταστρέφει αντικείµενα! Μέθοδοι Κάθε αντικείμενο διατηρεί την δική του μνήμη για τα πεδία δεδομένων του. Τα δεδομένα ενός αντικειμένου δεν μπορούν να τύχουν διαμοιρασμού με άλλα αντικείμενα. 19 20 Προκαθορισμένες Τιμές Πεδίων Αν δεν κάνουμε εμείς ρητή αρχικοποίηση των μελών αρχέγονου τύπου μιας κλάσης, ο μεταγλωττιστής δίνει τις δικές του προκαθορισμένες τιμές, ως εξής: Για boolea μεταβλητές: false Για άλλους αρχέγονους τύπους το 0. Διαχείριση Μνήµης στη Java µέσα από ένα παράδειγµα Για χειριστήρια αντικειμένων: ull 21 22 Text: δυαδικός (ιθαγενής / τελικός) κώδικας προγράμματος της διεργασίας. : σταθερές προγράμματος. (Block Started by Symbol (): γενικές και στατικές μεταβλητές (most moder assemblers produce a sectio i their output object module cotaiig all reserved uiitialized space). Heap: δυναμική μνήμη. Stack: στοίβα, τοπικές μεταβλητές. Text Heap (Σωρός) Stack (Στοίβα) 0xffffffff 23 0 Παράδειγμα Διαχείρισης Μνήμης 24
class CarFactory static it cout = 0; /** returs a tested ew Car */ public Car makeacar() Car ewc = ew Car(cout++); testcar(ewc); /* rus umtests o a give Car */ private void testcar(car testc) public static void mai(strig[] args) CarFactory cf = ew CarFactory(); Car vwoe = cf.makeacar(); 25 26 class CarFactory static it cout = 0; JVM loaded with bytecodes /** returs a tested ew Car */ class public CarFactory makeacar() class CarFactory ewc = ew Car(cout++); static testcar(ewc); it cout = 0; /** returs a tested ew Car */ /*/** public rus returs umtests Car makeacar() a tested o a give ew Car Car */ */ private public void Car testcar(car makeacar() testc) Car ewc = ew Car(cout++); testcar(ewc); testcar(ewc); static it cout = 0; Car ewc = ew Car(cout++); /* rus umtests o a give Car */ class /* private CarFactory rus umtests void testcar(car o a give testc) Car */ private static it void cout testcar(car = 0; testc) /** returs a tested ew Car */ public Car static makeacar() void mai(strig[] args) public static void mai(strig[] args) public static void mai(strig[] args) Car ewc CarFactory cf = ew = ew Car(cout++); CarFactory(); CarFactory vwoe = cf cf.makeacar(); = ew CarFactory(); testcar(ewc); vwoe = cf.makeacar(); CarFactory cf = ew CarFactory(); /* rus umtests Car vwoe o = a cf.makeacar(); give */ private void testcar(car testc) System.out.pritl(testC.getOdometer()); public static void mai(strig[] args) Text Heap (Σωρός) Η λειτουργία της στοίβας CarFactory cf = ew CarFactory(); Car vwoe = cf.makeacar(); Stack (Στοίβα) 27 28 class CarFactory static it cout = 0; Text Heap (Σωρός) /** returs a tested ew Car */ public Car makeacar() Car ewc = ew Car(cout++); testcar(ewc); Η λειτουργία του σωρού /* rus tests o a give Car */ private void testcar(car testc) public static void mai(strig[] args) CarFactory cf = ew CarFactory(); Car vwoe = cf.makeacar(); movecar testcar makeacar mai cf dist=10 dist=-20 testc ewc vwoe 29 30
Text class CarFactory static it cout = 0; /** returs a tested ew Car */ public Car makeacar() Car ewc = ew Car(cout++); testcar(ewc); Car CarFactory Heap /* rus tests o a give Car */ private void testcar(car testc) movecar dist=10 dist=-20 public static void mai(strig[] args) CarFactory cf = ew CarFactory(); Car vwoe = cf.makeacar(); testcar makeacar testc ewc mai cf vwoe Stack 31