Καλέστε μία φορά τη λειτουργία "DoStackOverflow" ο κωδικός σου και θα πάρετε το EStackOverflow λάθος που έθεσε ο Δελφός με το μήνυμα "υπερχείλιση στοίβας".
λειτουργία DoStackOverflow: ακέραιο;
ξεκινήσει
αποτέλεσμα: = 1 + DoStackOverflow;
τέλος;
Τι είναι αυτή η "στοίβα" και γιατί υπάρχει υπερχείλιση εκεί χρησιμοποιώντας τον παραπάνω κώδικα;
Έτσι, η λειτουργία DoStackOverflow καλείται αναδρομικά - χωρίς μια "στρατηγική εξόδου" - απλά συνεχίζει και δεν εξέρχεται ποτέ.
Μια γρήγορη λύση, θα κάνατε, είναι να καθαρίσετε το προφανές σφάλμα που έχετε και να διασφαλίσετε ότι η λειτουργία υπάρχει σε κάποιο σημείο (οπότε ο κώδικάς σας μπορεί να συνεχίσει να εκτελεί από εκεί που ονομάσατε τη λειτουργία).
Θα προχωρήσετε, και ποτέ δεν κοιτάτε πίσω, δεν φροντίζετε για το σφάλμα / εξαίρεση, όπως τώρα λύνεται.
Ωστόσο, το ερώτημα παραμένει: τι είναι αυτή η στοίβα και γιατί υπάρχει μια υπερχείλιση?
Μνήμη στις εφαρμογές των Δελφών σας
Όταν ξεκινάτε τον προγραμματισμό στους Δελφούς, μπορεί να αντιμετωπίσετε σφάλματα όπως αυτό παραπάνω, θα το λύσετε και θα προχωρήσετε. Αυτό σχετίζεται με την κατανομή μνήμης. Τις περισσότερες φορές δεν θα νοιαζόταν για την κατανομή μνήμης όσο εσείς
δωρεάν αυτό που δημιουργείτε.Καθώς αποκτάτε περισσότερη εμπειρία στους Δελφούς, ξεκινάτε να δημιουργείτε τις δικές σας τάξεις, να τις δημιουργείτε, να φροντίζετε για τη διαχείριση μνήμης και το ίδιο.
Θα φτάσετε στο σημείο όπου θα διαβάσετε, στη Βοήθεια, κάτι σαν "Οι τοπικές μεταβλητές (που δηλώνονται μέσα σε διαδικασίες και λειτουργίες) βρίσκονται σε μια εφαρμογή σωρός." και επίσης Οι κλάσεις είναι τύποι αναφοράς, επομένως δεν αντιγράφονται στην ανάθεση, διαβιβάζονται με παραπομπή και κατανέμονται στο σωρός.
Έτσι, τι είναι "στοίβα" και τι είναι "σωρός";
Stack vs. Σωρός
Εκτέλεση της εφαρμογής σας στα Windows, υπάρχουν τρεις περιοχές στη μνήμη όπου η εφαρμογή σας αποθηκεύει δεδομένα: παγκόσμια μνήμη, σωρό και στοίβα.
Οι συνολικές μεταβλητές (οι τιμές / τα δεδομένα τους) αποθηκεύονται στην παγκόσμια μνήμη. Η μνήμη για τις συνολικές μεταβλητές διατηρείται από την εφαρμογή σας όταν ξεκινά το πρόγραμμα και παραμένει κατανεμημένο μέχρι να τερματιστεί το πρόγραμμα. Η μνήμη για τις συνολικές μεταβλητές ονομάζεται "τμήμα δεδομένων".
Δεδομένου ότι η καθολική μνήμη χορηγείται μόνο μία φορά και απελευθερώνεται με τερματισμό του προγράμματος, δεν μας νοιάζει αυτό σε αυτό το άρθρο.
Στοίβα και σωρός είναι όπου γίνεται δυναμική κατανομή μνήμης: όταν δημιουργείτε μια μεταβλητή για μια λειτουργία, όταν δημιουργείτε μια εμφάνιση μιας κλάσης όταν στέλνετε παραμέτρους σε μια λειτουργία και χρησιμοποιείτε / περάσατε το αποτέλεσμα της αξία.
Τι είναι η στοίβα;
Όταν δηλώνετε μια μεταβλητή μέσα σε μια συνάρτηση, η μνήμη που απαιτείται για τη διατήρηση της μεταβλητής κατανέμεται από τη στοίβα. Απλά γράφετε "var x: integer", χρησιμοποιήστε το "x" στη λειτουργία σας και όταν η λειτουργία εξέρχεται, δεν σας ενδιαφέρει η μνήμη και η απελευθέρωση. Όταν η μεταβλητή σβήσει από το πεδίο εφαρμογής (ο κώδικας εξέρχεται από τη λειτουργία), η μνήμη που λήφθηκε στη στοίβα ελευθερώνεται.
Η μνήμη στοίβας κατανέμεται δυναμικά χρησιμοποιώντας την προσέγγιση LIFO ("last in first out").
Σε Προγράμματα Delphi, η μνήμη στοίβας χρησιμοποιείται από
- Τοπικές ρουτίνες (μέθοδος, διαδικασία, λειτουργία) μεταβλητές.
- Παράμετροι ρουτίνας και τύποι επιστροφής.
- Η λειτουργία API των Windows κλήσεις.
- Εγγραφές (γι 'αυτό δεν χρειάζεται να δημιουργήσετε ρητά μια παρουσία τύπου εγγραφής).
Δεν χρειάζεται να απελευθερώσετε ρητώς τη μνήμη στη στοίβα, καθώς η μνήμη έχει μοιραστεί αυτόματα για εσάς όταν, για παράδειγμα, δηλώσετε μια τοπική μεταβλητή σε μια λειτουργία. Όταν η λειτουργία εξέρχεται (μερικές φορές ακόμη και πριν από τη βελτιστοποίηση του μεταγλωττιστή Delphi), η μνήμη για τη μεταβλητή θα απελευθερωθεί αυτόματα.
Μέγεθος μνήμης στοίβας είναι, από προεπιλογή, αρκετά μεγάλη για τα δικά σας προγράμματα (όπως είναι πολύπλοκα όπως είναι τα Delphi). Οι τιμές "Μέγιστο μέγεθος στοίβας" και "Ελάχιστο μέγεθος στοίβας" στις επιλογές Linker για το έργο σας καθορίζουν τις προεπιλεγμένες τιμές - στο 99,99% δεν θα χρειαστεί να αλλάξετε αυτό.
Σκεφτείτε μια στοίβα ως ένα σωρό μπλοκ μνήμης. Όταν δηλώνετε / χρησιμοποιείτε μια τοπική μεταβλητή, ο διαχειριστής μνήμης Delphi θα επιλέξει το μπλοκ από την κορυφή, θα το χρησιμοποιήσει και όταν δεν χρειάζεται πια, θα επιστρέψει στη στοίβα.
Με τη χρήση μνήμης τοπικής μεταβλητής από τη στοίβα, οι τοπικές μεταβλητές δεν αρχικοποιούνται όταν δηλώνονται. Δηλώστε μια μεταβλητή "var x: integer" σε κάποια λειτουργία και δοκιμάστε να διαβάσετε την τιμή όταν εισάγετε τη λειτουργία - το x θα έχει κάποια "παράξενη" μη μηδενική τιμή. Επομένως, πάντα να αρχικοποιήσετε (ή να ορίσετε τιμή) στις τοπικές μεταβλητές πριν διαβάσετε την αξία τους.
Λόγω του LIFO, οι λειτουργίες stack (κατανομής μνήμης) είναι γρήγορες καθώς μόνο λίγες λειτουργίες (push, pop) απαιτούνται για τη διαχείριση μιας στοίβας.
Τι είναι σωρός;
Ένας σωρός είναι μια περιοχή μνήμης στην οποία αποθηκεύεται δυναμικά κατανεμημένη μνήμη. Όταν δημιουργείτε μια εμφάνιση μιας κλάσης, η μνήμη εκχωρείται από τον σωρό.
Στα προγράμματα Delphi, η μνήμη σωρού χρησιμοποιείται από / πότε
- Δημιουργία μιας παρουσίας μιας κλάσης.
- Δημιουργία και αλλαγή μεγέθους δυναμικών συστοιχιών.
- Κατανοώντας ρητά τη μνήμη χρησιμοποιώντας τα GetMem, FreeMem, New και Dispose ().
- Χρησιμοποιώντας σειρές ANSI / ευρύ / Unicode, παραλλαγές, διεπαφές (που διαχειρίζονται αυτόματα οι Δελφοί).
Η μνήμη σωρού δεν έχει ωραία διάταξη, όπου θα υπήρχε κάποια τάξη, η οποία κατανέμει μπλοκ μνήμης. Ο σωρός μοιάζει με ένα δοχείο από μάρμαρα. Η κατανομή μνήμης από τον σωρό είναι τυχαία, ένα τετράγωνο από εδώ, από ένα μπλοκ από εκεί. Έτσι, οι λειτουργίες σωρού είναι λίγο πιο αργές από εκείνες της στοίβας.
Όταν ζητάτε ένα νέο μπλοκ μνήμης (δηλ. Δημιουργήστε μια παρουσία μιας κλάσης), ο διαχειριστής μνήμης Delphi θα το χειριστεί για σας: θα πάρετε ένα νέο μπλοκ μνήμης ή ένα χρησιμοποιημένο και απορριφθέν.
Ο σωρός αποτελείται από όλες τις εικονικές μνήμες (RAM και χώρο στο δίσκο).
Μη αυτόματη κατανομή μνήμης
Τώρα που όλα σχετικά με τη μνήμη είναι σαφή, μπορείτε με ασφάλεια (στις περισσότερες περιπτώσεις) να αγνοήσετε τα παραπάνω και απλά να συνεχίσετε να γράφετε προγράμματα Delphi όπως κάνατε χθες.
Φυσικά, θα πρέπει να γνωρίζετε πότε και πώς να διαθέτετε / ελεύθερη μνήμη με το χέρι.
Το "EStackOverflow" (από την αρχή του άρθρου) τέθηκε επειδή με κάθε κλήση στο DoStackOverflow χρησιμοποιήθηκε ένα νέο τμήμα μνήμης από τη στοίβα και η στοίβα έχει περιορισμούς. Τόσο απλό.