
Python χρησιμοποιεί τη μέθοδο καταμέτρηση αναφορά για να χειριστεί το χρόνο αντικείμενο ζωή. Έτσι, ένα αντικείμενο που δεν έχει περισσότερη χρήση θα πρέπει να καταστρέφονται αμέσως.


Αλλά, στην Ιάβα, το GC (συλλέκτης σκουπιδιών) καταστρέφει τα αντικείμενα που δεν χρησιμοποιούνται πλέον σε μια συγκεκριμένη χρονική στιγμή.


Γιατί η Java επιλέξετε αυτή τη στρατηγική και ποιο είναι το όφελος από αυτό;


Αυτή είναι η καλύτερη από την προσέγγιση Python;

 
Γιατί μεθόδους συλλογής σκουπιδιών Java και Python είναι διαφορετικά;
=====================================================================



Υπάρχουν μειονεκτήματα της χρησιμοποιώντας μέτρηση αναφοράς. Ένα από τα πιο αναφέρθηκε είναι κυκλικές αναφορές: Ας υποθέσουμε ότι ένας αναφορές Β, Β αναφοράς C και C ΑΝΑΦΟΡΕΣ B. Εάν το Α ήταν να πέσει η αναφορά του σε Β, αμφότερα Β και Γ ακόμα θα έχουν μια καταμέτρηση αναφοράς 1 και δεν θα διαγραφούν με την παραδοσιακή μέτρηση αναφοράς. CPython (μέτρηση αναφοράς δεν αποτελεί μέρος της ίδιας της python, αλλά στο πλαίσιο της εφαρμογής C αυτών) πιάνει κυκλικές αναφορές με ξεχωριστή ρουτίνα συλλογή των απορριμμάτων ώστε να εκτελείται περιοδικά ...


Ένα άλλο μειονέκτημα: μέτρηση αναφοράς μπορεί να κάνει πιο αργή εκτέλεση. Κάθε φορά που ένα αντικείμενο αναφέρεται και αναχθούν, ο διερμηνέας / VM πρέπει να ελέγξετε για να δείτε αν ο αριθμός έχει μειωθεί στο 0 (και στη συνέχεια deallocate αν το έκανε). Η συλλογή σκουπιδιών δεν χρειάζεται να το κάνουμε αυτό.


Επίσης, Συλλογή σκουπιδιών μπορεί να γίνει σε ένα ξεχωριστό νήμα (αν και μπορεί να είναι λίγο δύσκολο). Σε μηχανήματα με πολλά RAM και για τις διαδικασίες που χρησιμοποιούν μνήμη με αργούς ρυθμούς, μπορεί να μην θέλετε να κάνετε GC σε όλα! καταμέτρηση αναφοράς θα είναι ένα κομμάτι από ένα μειονέκτημα εκεί όσον αφορά τις επιδόσεις ...

 

Νομίζω ότι το άρθρο « [Java θεωρία και πράξη: Μια σύντομη ιστορία της συλλογής σκουπιδιών](http://www.ibm.com/developerworks/java/library/j-jtp10283/) » από την IBM θα πρέπει να εξηγήσει μερικές από τις ερωτήσεις που έχετε.

 

Darren Thomas δίνει μια καλή απάντηση. Ωστόσο, μια μεγάλη διαφορά μεταξύ της Java και Python προσεγγίσεις είναι ότι με την καταμέτρηση αναφορά στην κοινή υπόθεση είναι (όχι κυκλικές αναφορές) αντικείμενα που καθαρίζονται αμέσως και όχι σε κάποιο απροσδιόριστο μέλλον.


Για παράδειγμα, μπορώ να γράψει προχειρότητα, μη-φορητή κώδικα σε CPython όπως



```
def parse_some_attrs(fname):
    return open(fname).read().split("~~~")[2:4]

```

και η περιγραφέα αρχείου για το αρχείο άνοιξα θα πρέπει να καθαρίζονται αμέσως, διότι μόλις η αναφορά στο άνοιγμα του αρχείου πηγαίνει μακριά, το αρχείο είναι σκουπίδια συλλέγονται και ο περιγραφέας αρχείου ελευθερώνεται. Φυσικά, αν τρέχω Jython ή IronPython ή ενδεχομένως PyPy, τότε ο συλλέκτης σκουπιδιών δεν θα είναι απαραίτητα διαρκέσει μέχρι πολύ αργότερα? ενδεχομένως θα ξεμείνει από περιγραφείς αρχείων πρώτο και το πρόγραμμα μου θα συντριβή.


Έτσι θα πρέπει να γράφετε κώδικα που μοιάζει με



```
def parse_some_attrs(fname):
    with open(fname) as f:
        return f.read().split("~~~")[2:4]

```

αλλά μερικές φορές οι άνθρωποι ήθελαν να βασίζονται σε καταμέτρηση αναφορά πάντα απελευθερώσει πόρους τους, επειδή μερικές φορές μπορεί να κάνει κωδικό σας λίγο μικρότερη.


Θα έλεγα ότι η καλύτερη συλλέκτης σκουπιδιών είναι αυτός με την καλύτερη απόδοση, που φαίνεται σήμερα να είναι η Java στιλ γενεών συλλέκτες σκουπιδιών που μπορεί να τρέξει σε ένα ξεχωριστό νήμα και να έχει όλα αυτά τα τρελά βελτιστοποιήσεις, κλπ Οι διαφορές με τον τρόπο που γράφουν κώδικα σας θα πρέπει να είναι αμελητέες και ιδανικά ανύπαρκτη.

 

Η τελευταία Sun Java VM έχουν πραγματικά πολλούς αλγόριθμους GC που μπορείτε να ρυθμίσετε. Οι προδιαγραφές Java VM σκόπιμα παραλείπεται προσδιορίζει την πραγματική συμπεριφορά GC για να επιτρέψει διαφορετικά (και πολλούς) αλγορίθμων GC για διαφορετικούς ΚΟ.


Για παράδειγμα, για όλους τους ανθρώπους που αντιπαθούν την προσέγγιση "stop-the-world" του προεπιλεγμένου Sun Java VM συμπεριφορά GC, υπάρχουν VM, όπως [WebSphere Real Time της IBM](http://www-01.ibm.com/software/webservers/realtime/) η οποία επιτρέπει την εφαρμογή σε πραγματικό χρόνο να τρέχει σε Java.


Από το spec Java VM είναι διαθέσιμες στο κοινό, δεν υπάρχει (θεωρητικά) τίποτα να σταματήσει κανείς από την εφαρμογή Java VM που χρησιμοποιεί τον αλγόριθμο GC CPython του.

 

καταμέτρηση αναφοράς είναι ιδιαίτερα δύσκολο να γίνει αποτελεσματικά σε ένα πολυ-σπείρωμα περιβάλλον. Δεν ξέρω πώς θα αρχίσουν ακόμη και να το κάνουμε χωρίς να εμπλακούμε σε συναλλαγές υλικό υποβοηθούμενη ή παρόμοιο (επί του παρόντος) ασυνήθιστη ατομική οδηγίες.


καταμέτρηση αναφοράς είναι εύκολο να εφαρμοστούν. JVMs είχαν πολλά χρήματα βυθίστηκε σε ανταγωνιστικές υλοποιήσεις, γι 'αυτό δεν πρέπει να προκαλεί έκπληξη το γεγονός ότι εφαρμόζουν πολύ καλές λύσεις σε πολύ δύσκολα προβλήματα. Ωστόσο, είναι όλο και πιο εύκολο να στοχεύσετε αγαπημένη σας γλώσσα στο JVM.

 

Συλλογή των απορριμμάτων είναι πιο γρήγορα (πιο αποδοτικό χρόνο) από την καταμέτρηση αναφοράς, αν έχετε αρκετή μνήμη. Για παράδειγμα, ένας GC αντιγραφή διασχίζει τα «ζωντανά» τα αντικείμενα και τα αντίγραφα τους σε ένα νέο χώρο, και μπορεί να διεκδικήσει εκ νέου όλα τα «νεκρά» αντικείμενα σε ένα βήμα, χαράσσοντας ολόκληρη την περιοχή της μνήμης. Αυτό είναι πολύ αποτελεσματικό, *αν* έχετε αρκετή μνήμη. Γενεών συλλογές χρησιμοποιούν τη γνώση ότι «τα περισσότερα αντικείμενα που πεθαίνουν νέοι»? συχνά μόνο ένα μικρό ποσοστό των αντικειμένων που πρέπει να αντιγραφεί.


[Αυτό είναι και ο λόγος που GC μπορεί να είναι ταχύτερη από ό, τι malloc / δωρεάν]


καταμέτρηση αναφοράς είναι πολύ πιο αποτελεσματική από χώρο συλλογής απορριμμάτων, δεδομένου ότι διεκδικεί τη μνήμη την ίδια στιγμή που γίνεται απρόσιτο. Αυτό είναι ωραίο όταν θέλετε να επισυνάψετε finalizers σε αντικείμενα (π.χ. να κλείσει ένα αρχείο αφού το αντικείμενο αρχείου γίνεται απρόσιτο). Ένα σύστημα καταμέτρησης αναφοράς μπορεί να λειτουργήσει ακόμα και όταν μόνο ένα μικρό ποσοστό της μνήμης είναι ελεύθερη. Αλλά το κόστος διαχείρισης του να πρέπει να αυξήσετε και μετρητές μείωση μετά από κάθε ανάθεση δείκτη κοστίσει πολύ χρόνο, και κάποιο είδος συλλογής απορριμμάτων εξακολουθεί να είναι απαραίτητη για να διεκδικήσουν κύκλους.


Έτσι, το εμπόριο-off είναι σαφής: αν έχετε να εργαστούν σε μια μνήμη-περιορισμένο περιβάλλον, ή αν χρειάζεστε ακριβή finalizers, χρησιμοποιήστε καταμέτρηση αναφοράς. Εάν έχετε αρκετή μνήμη και χρειάζονται την ταχύτητα, χρησιμοποιήστε τη συλλογή σκουπιδιών.

 

Στην πραγματικότητα καταμέτρηση αναφοράς και οι στρατηγικές που χρησιμοποιούνται από τον Ήλιο JVM είναι όλα διαφορετικά είδη των αλγορίθμων συλλογής απορριμμάτων.


Υπάρχουν δύο γενικές προσεγγίσεις για τον εντοπισμό νεκρών αντικειμένων: ανίχνευση και καταμέτρηση αναφοράς. Κατά τον εντοπισμό του GC ξεκινά από τις «ρίζες» - πράγματα όπως αναφορές στοίβα, και τα ίχνη όλα προσβάσιμα (live) αντικείμενα. Κάτι που δεν μπορεί να επιτευχθεί θεωρείται νεκρός. Στην αναφορά μετρώντας κάθε φορά που γίνεται αναφορά τροποποίησε το αντικείμενο που εμπλέκονται έχουν ενημερωθεί καταμέτρηση τους. Κάθε αντικείμενο του οποίου η καταμέτρηση αναφορά που παίρνει στο μηδέν θεωρείται νεκρός.


Με βάση όλες τις εφαρμογές GC υπάρχουν συμβιβασμούς, αλλά η παρακολούθηση είναι συνήθως καλό για την υψηλή μέσω βάλει (π.χ. γρήγορη) λειτουργία, αλλά έχει μεγαλύτερους χρόνους παύσης (μεγαλύτερα κενά όπου το UI ή το πρόγραμμα μπορεί να παγώσει). καταμέτρηση αναφοράς μπορεί να λειτουργήσει σε μικρότερα κομμάτια, αλλά θα είναι πιο αργή συνολικά. Αυτό μπορεί να σημαίνει λιγότερο παγώνει, αλλά φτωχότερη συνολική απόδοση.


Επιπλέον, η αναφορά μετράει GC απαιτεί έναν ανιχνευτή κύκλο για να καθαρίσει όλα τα αντικείμενα σε ένα κύκλο που δεν μπορεί να αλιευθεί μόνο από την καταμέτρηση αναφοράς τους. Perl 5 δεν έχουν ανιχνευτή κύκλο στην εφαρμογή GC του και θα μπορούσε να προκαλέσει απώλεια μνήμης που ήταν κυκλική.


Η έρευνα έχει επίσης γίνει για να πάρει το καλύτερο και των δύο κόσμων (φορές χαμηλή παύση, υψηλής απόδοσης):
 <http://cs.anu.edu.au/~Steve.Blackburn/pubs/papers/urc-oopsla-2003.pdf>

 

Αργά το παιχνίδι, αλλά νομίζω ότι ένα σημαντικό σκεπτικό για RC σε python είναι η απλότητά του. Δείτε αυτό το [μήνυμα ηλεκτρονικού ταχυδρομείου από τον Alex Martelli](http://mail.python.org/pipermail/python-list/2005-October/921938.html) , για παράδειγμα.


(Δεν μπόρεσα να βρω έναν σύνδεσμο έξω από το google μνήμη cache, την ημερομηνία e-mail από τις 13 Οκτωβρίου 2005 σχετικά με κατάλογο python).

 

Ένα μεγάλο μειονέκτημα της ανίχνευσης GC Java είναι ότι από καιρό σε καιρό θα «σταματήσει τον κόσμο» και να παγώσει την αίτηση για ένα σχετικά μεγάλο χρονικό διάστημα για να κάνει μια πλήρη GC. Αν ο σωρός είναι μεγάλο και το το συγκρότημα δέντρο αντικείμενο, θα παγώσει για μερικά δευτερόλεπτα. Επίσης κάθε πλήρες GC επισκέπτεται όλο το δέντρο αντικείμενο ξανά και ξανά, κάτι που είναι ίσως αρκετά αναποτελεσματική. Ένα άλλο μειονέκτημα του τρόπου Java κάνει GC είναι ότι θα πρέπει να πω το JVM τι μέγεθος σωρού που θέλετε (αν η προεπιλογή δεν είναι αρκετά καλό)? το JVM προέρχεται από αυτή την τιμή αρκετά κατώτατα όρια που θα ενεργοποιήσουν τη διαδικασία GC όταν υπάρχει πάρα πολύ τα σκουπίδια στοίβαγμα επάνω στο σωρό.


Υποθέτω ότι αυτό είναι στην πραγματικότητα η κύρια αιτία της σπασμωδικές αίσθηση του Android (που βασίζεται σε Java), ακόμα και για τα πιο ακριβά κινητά τηλέφωνα, σε σύγκριση με την ομαλότητα του iOS (με βάση την δημιουργία αρχείο, και χρησιμοποιώντας RC). 


Θα ήθελα πολύ να δω μια επιλογή JVM για να ενεργοποιήσετε διαχείριση μνήμης RC, και ίσως κρατώντας GC μόνο να τρέξει ως ύστατη λύση, όταν δεν υπάρχει περισσότερη μνήμη αριστερά. 

 