Δέσμευση μνήμης και χρόνος ζωής — DedSec Project
Μνήμη και πόροι — σωστό κλείσιμο ακόμη και μετά από σφάλμα Συμβόλαιο χρόνου ζωής Το ότι ένα αντικείμενο παραμένει προσβάσιμο, το ότι κατέχει έναν πόρο και το ότι ο πόρος είναι ανοιχτός…
Μνήμη και πόροι — σωστό κλείσιμο ακόμη και μετά από σφάλμα
Συμβόλαιο χρόνου ζωής
Το ότι ένα αντικείμενο παραμένει προσβάσιμο, το ότι κατέχει έναν πόρο και το ότι ο πόρος είναι ανοιχτός αποτελούν διαφορετικές ιδιότητες. Η Python μπορεί να αποδεσμεύει συνηθισμένη μνήμη μέσω καταμέτρησης αναφορών ή συλλογής απορριμμάτων, αλλά ένα αρχείο ή μία σύνδεση χρειάζεται ξεκάθαρο κλείσιμο, χωρίς να περιμένει απροσδιόριστο κύκλο συλλογής. Στη C, επιστροφή δείκτη προς τοπική αυτόματη μεταβλητή δημιουργεί μη έγκυρη αναφορά. Η Rust επιβάλλει κανόνες ιδιοκτησίας και δανεισμού πριν την εκτέλεση. Ακόμη και στις γλώσσες υψηλού επιπέδου, η διαχείριση εξωτερικών πόρων παραμένει ευθύνη μας.
Εκτελέσιμο εργαστήριο Python 3
Αποθήκευσε ως lifetime_lab.py και εκτέλεσε python3 lifetime_lab.py. Η ExitStack καταχωρίζει τους πόρους και τους κλείνει με αντίστροφη σειρά ακόμη και όταν προκληθεί σκόπιμο σφάλμα στην επεξεργασία.
from contextlib import ExitStack
from io import StringIO
closed = []
class Tracked(StringIO):
def __init__(self, name):
super().__init__(name)
self.name = name
def close(self):
if not self.closed:
closed.append(self.name)
super().close()
first, second = Tracked("first"), Tracked("second")
try:
with ExitStack() as stack:
a = stack.enter_context(first)
b = stack.enter_context(second)
assert a.read() == "first" and b.read() == "second"
raise RuntimeError("simulated parse failure")
except RuntimeError:
pass
assert first.closed and second.closed
assert closed == ["second", "first"]
print("PASS: reverse-order cleanup on failure")
Τι αποδεικνύει ο έλεγχος
Και οι δύο προσωρινοί χειριστές κλείνουν μετά την εξαίρεση. Η δεύτερη εγγραφή καθαρίζεται πριν από την πρώτη, καθώς οι διαχειριστές συμφραζομένων αποδεσμεύονται με αντίστροφη σειρά. Η ExitStack είναι χρήσιμη όταν ο αριθμός των απαιτούμενων πόρων αποφασίζεται κατά την εκτέλεση. Αν αποτύχει το άνοιγμα τρίτου πόρου, οι δύο προηγούμενοι πρέπει να καθαριστούν. Το παράδειγμα δεν μετρά τον χρόνο συλλογής απορριμμάτων ούτε εγγυάται απουσία διαρροών από ξένες βιβλιοθήκες.
Ασκήσεις και διάγνωση
- Πρόσθεσε τρίτο χειριστή, προκάλεσε εξαίρεση πριν καταχωριστεί και βεβαιώσου ποιοι ακριβώς καθαρίζονται.
- Αφαίρεσε προσωρινά την ExitStack, σύγκρινε εγγυημένο κλείσιμο με ενδεχόμενη αποδέσμευση και επανάφερέ την.
- Σχεδίασε cache που αποθηκεύει διαδρομές αντί ανοιχτών αρχείων και ανέλυσε τις συνέπειες στην ταχύτητα και στην παλαιότητα δεδομένων.
- Περιέγραψε τους αντίστοιχους κανόνες για malloc/free στη C και μετακινήσεις ή δανεισμούς στη Rust. Αν χρησιμοποιήσεις ελεγκτές μνήμης, περιορίσου σε προσωρινά δείγματα.
Παραδοτέα: PASS, σειρά κλεισίματος, ίχνος εξαίρεσης και σχεδιάγραμμα ιδιοκτησίας. Ξεχώρισε αποδέσμευση μνήμης από κλείσιμο πόρων λειτουργικού συστήματος.