Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Ποιός έχει reference στο object αυτό;

Îåêßíçóå áðü ôï ìÝëïò Sunburn. Τελευταία δημοσίευση από το μέλος Παναγιώτης Καναβός στις 20-08-2008, 18:56. Υπάρχουν 6 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  14-08-2008, 14:47 44109

    Ποιός έχει reference στο object αυτό;

    'Αλλο ένα "περίεργο" πρόβλημα για το οποίο δεν έχω βρει ακόμα λύση.

    Δημιουργώ λοιπόν ένα object. Στη συνέχεια, και κατα τη διάρκεια του όλου κύκλου ζωής του, αυτό το object προστίθεται σε διάφορες collections, γίνεται referenced από εκατοντάδες άλλα objects σε κάποιο property τους, γενικά γίνεται αυτό που θα λέγαμε "ενεργό μέλος της τοπικής κοινωνίας" μέσα στο σύμπαν της εφαρμογής.

    Μέχρι που έρχεται η ώρα να "σκοτωθεί". Και τώρα πρέπει να ψάξω όλες τις collections μια μια, όλα τα άλλα objects που πιθανόν να το κάνουν reference και να πω σε κάθε έναν "αυτό το object ξέγραψέ το από τα κιτάπια σου".

    Το προβλημα σε μια τέτοια διαδικασία, ειδικά όταν ο αριθμός των objects & collections που μπορεί να "γνωρίζουν" το object αυτό έιναι μεγάλος, είναι πως έιναι εύκολο να σου ξεφύγει κάποιος. Και έστω κι ένας να απομέινει που "θυμάται" το object αυτό, ο GC θα αρνηθεί να το σκοτώσει (και με το δικιο του). Πέρα από το αυτονόητο memory leak που συνεπάγεται αυτό (καθότι συνεχώς δημιουργούνται καινούργια objects που τελικά ποτέ δεν σκοτώνονται οριστικά για να ελευθερωθούν τα resources τους), υπάρχει και ο σοβαρός κίνδυνος οτι οι τυχόν stragglers (τα objects/collections τα οποία κακώς δεν ενημερώθηκαν να αφαιρέσουν to object αυτό από τα κιτάπια τους) πάνε στη συνέχεια να κάνουν κάτι με το Object αυτό (πιστέυοντας οτι ακόμα ζει και βασιλεύει) και τρώνε ενα μεγαλοπρεπές άκυρο. (Crash-boom-bang).

    Το ερώτημα/πρόβλημα λοιπόν είναι:
    * Αντί να χρειάζεται να ψιθυρίσω τα νέα του θανάτου στο αυτί του κάθε κατοικου του χωριού ξεχωριστά, μπορώ με κάποιο τρόπο να το βροντοφωνάξω από την κεντρική πλατεία και να έχω guarrantee πως όλοι οι ενδιαφερόμενοι θα το ακούσουν;
    * Εαν αυτό δεν έιναι εφικτό, γίνεται εναλλακτικά να αποκτήσω μια λίστα αυτών των ενδιαφερομένων έτσι ώστε να τους ενημερώσω "χειροκίνητα" με τη σιγουριά οτι δεν μου ξέφυγε κανένας;

    Απο ότι γνωρίζω, ο τρόπος που λειτουργεί ο GC (reference counting) είναι κάτι αντίστοιχο, δηλ. κοιτά να δεί εαν ένα object είναι referenced από οτιδήποτε άλλο και αν όχι, το σκοτώνει οριστικά. Υπάρχει κάποια αντίστοιχη δυνατότητα μέσω κώδικα; (Ένα property του στυλ object.ReferencedBy() as IEnumerable(of Object) θα ήταν πολύ κοντά στο ιδανικό).

    Οποιαδήποτε βοήθεια στο ζήτημα καλοδεχόυμενη.



     
  •  14-08-2008, 15:48 44113 σε απάντηση της 44109

    Απ: Ποιός έχει reference στο object αυτό;

    Γιατί δεν χρησιμοποιείς απλά Events στο Insert και στο Delete απο τα Collections στα οποία απλά θα ακούνε τα Objects σου και ανάλογα θα πράτουν;
    Παναγιώτης Κεφαλίδης

    "Για να επιτύχεις, θα πρέπει το πάθος σου για την επιτυχία να είναι μεγαλύτερο απο τον φόβο σου για την αποτυχία"

    Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Παρακαλώ διαβάστε τους όρους χρήσης.
  •  14-08-2008, 17:07 44116 σε απάντηση της 44113

    Απ: Ποιός έχει reference στο object αυτό;

    Αυτό κάνω πάντα μέχρι τώρα, και τις περισσότερες φορές με εξυπηρετεί ικανοποιητικά. Επειδή όμως είναι μια κάπως ιδιόμορφη εφαρμογή, με αρκετά περίπλοκο object model το οποίο σχεδόν συνεχώς εξελίσσεται/μεταλλάσεται, αναζητώ και εναλλακτικούς τρόπους μήπως και κάποτε έρθει η στιγμή που θα έιναι πολύ πιο cost-effective να κάνω κάτι τετοιο παρά να ψάχνω σε 20-30 διαφορετικές collections για να βεβαιώσω οτι έχω βάλει κατάλληλα event handlers στην καθεμία.
  •  16-08-2008, 16:22 44139 σε απάντηση της 44116

    Απ: Ποιός έχει reference στο object αυτό;

    Μπορείς να χρησιμοποιήσεις την κλάση WeakReference για να δημιουργήσεις references τα οποία δεν εμποδίζουν το garbage collection ενός αντικειμένου. Έτσι όμως θα έχεις πρόβλημα με null references μέσα στα collections. Μπορείς να κάνεις dispose το αντικείμενο σου μόνο που και τότε θα έχεις ένα αντίστοιχο πρόβλημα, με τη διαφορά ότι τώρα θα έχεις ένα "σκοτωμένο" αντικείμενο αντί για null reference.

    Νομίζω ότι θα πρέπει να ξανασκεφτείς το object model σου. Η όλη ιδέα του garbage collection είναι ότι δεν σε ενδιαφέρει και τόσο πότε καταστρέφεται ένα αντικείμενο. Μήπως το έχεις παρακάνει με τα πολλά collections? Ένα collection παρέχει δύο υπηρεσίες: "κρατάει" αντικείμενα και παρέχει τρόπο αναζήτησης και enumeration. Υποθέτω ότι για να έχεις το ίδιο αντικείμενο σε πολλά διαφορετικά collections μάλλον θέλεις διαφορετικούς τρόπους αναζήτησης ή enumeration. Αυτό όμως μπορείς να το πετύχεις καλύτερα χρησιμοποιώντας είτε εξειδικευμένα functions για την αναζήτηση, είτε δημιουργώντας iterators τα οποία θα δουλεύουν όπως θες.

    Επίσης, αν χρησιμοποιείς τα collections για να δημιουργήσεις ουσιαστικά διαφορετικά "views" των δεδομένων σου, η καλύτερη λύση θα είναι να χρησιμοποιείς προσωρινά collections στη μνήμη. Αν για παράδειγμα θέλεις να επιστρέψεις μόνο τους πρώτους 5 πελάτες μπορείς να τους επιστρέψεις ως List<Customer> από το Data Layer σου αλλά να μην αποθηκεύσεις αυτό το collection στο business ή στο presentation layer.

    Το LINQ σου δίνει άλλη μία λύση καθώς σου επιτρέπει να κάνεις queries τα οποία επιστρέφουν τα δεδομένα με όποια μορφή θέλεις χωρίς να πρέπει εσύ να χειριστείς πολλαπλά collections. Κρατάς τα αντικείμενα σου σε ένα κεντρικό collection και μετά κάνεις queries επάνω σε αυτό.

    Αν δώσεις περισσότερες λεπτομέρειες για το τί προσπαθείς να κάνεις ίσως να υπάρχουν και άλλες λύσεις.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  19-08-2008, 11:40 44155 σε απάντηση της 44139

    Απ: Ποιός έχει reference στο object αυτό;

    Μια άλλη λύση, θα ήταν να χρησιμοποιήσεις το Serialization για να πάρεις ένα object graph (πχ σε xml) μέσα από το οποίο θα μπορείς να δεις ποιά objects έχουν reference στο object που σε ενδιαφέρει.


    Vir prudens non contra ventum mingit
  •  20-08-2008, 12:36 44189 σε απάντηση της 44155

    Απ: Ποιός έχει reference στο object αυτό;

    Νομίζω πως θα χρησιμοποιήσω ένα συνδιασμό των λύσεων που προτάθηκαν. Θα φροντίσω να ενωματώσω μια ρουτίνα ενημέρωσης "κάθε ενδιαφερομένων" στο change notification της "master object collection" ωστε να ενημερώνονται όλοι οι υπόλοιποι.

    Απάντηση στον Παναγιώτη: Στις περισσότερες εφαρμογές, το να υπάρχει μια κεντρική λίστα και με βάση αυτή να δημιουργούνται dynamic views on-the-fly είναι η πιο σωστή τακτική (βασικά για τους ίδιους λόγους που κάνουμε normalization σε μια DB). Ωστόσο στην συγκεκριμένη περίπτωση τα performance constraints είναι αρκετά σφικτά (πρόκειται για ένα real-time simulation) και είναι πολύ πιο αποδοτικό τα διάφορα collections, references κλπ. να ενημερώνονται απαξ στην αρχή κάθε "παλμού" και να παραμένουν στατικά για προσπέλαση στη διάρκειά του (και να αλλάζουν μόνο "με το χέρι"), παρά να παρουσιάζονται ως dynamic properties που θα πρέπει να υπολογιστούν on-the-fly π.χ. 2000-3000 φορές σε κάθε παλμό (γιατί τόσες φορές θα προσπελαστούν).

    Σε κάθε περίπτωση, εκτιμώ τη βοήθεια και σας ευχαριστώ για όλες τις προτάσεις.
  •  20-08-2008, 18:56 44193 σε απάντηση της 44189

    Απ: Ποιός έχει reference στο object αυτό;

    Τα views ήταν απλά ένα παράδειγμα για το ότι ο τρόπος χρήσης υπαγορεύει τη λύση. Ειδικά στην περίπτωση του simulation μπορείς να χρησιμοποιήσεις διάφορες τεχνικές για να αποφύγεις τα events τα οποία θα έχουν τη δική τους επίδραση στο performance.

    • Αν μπορείς να περιορίσεις τη χρήση των collections και των αντικειμένων σε μία μόνο εκτέλεση του simulation, μπορείς να τις ορίσεις στα πλαίσια μίας κλάσης SimulationRun και να πραγματοποιήσεις όλους τους υπολογισμούς σου μέσα στην SimulationRun χωρίς να ξεφεύγουν references προς τα έξω. Έτσι όταν η SimulationRun βγει εκτός scope όλα τα collections και τα αντικείμενα θα είναι διαθέσιμα για garbage collection.
    • Στην περίπτωση που θέλεις τα αντικείμενα να καθαρίζονται κάθε φορά που εκτελείται ένα simulation event (όχι .NET event) μπορείς να χρησιμοποιήσεις την ίδια τεχνική με το SimulationRun. Περιόρισε όλα τα references στα πλαίσια ενός SimulationEvent αντικειμένου και μην αφήνεις να ξεφύγουν προς τα έξω.
    • Αν θέλεις να περιορίσεις τη χρήση μνήμης κάνεις override την dispose της SimulationRun για να κάνει με τη σειρά της Dispose τα collections της και κατ' επέκταση τα αντικείμενα της. Θα μπορούσες να κάνεις το ίδιο και με την SimulationEvent αλλά εδώ υπάρχει η πιθανότητα το κόστος των Dispose να είναι μεγαλύτερο από το όφελος. Ίσως βοηθήσει η εκτέλεση ενός χειροκίνητου garbage collection σε κάθε Run έτσι ώστε να καθαρίσουν όλα τα νεκρά αντικείμενα των Events. Αυτό όμως θα το δείξουν οι δοκιμές σου.
    • Στην περίπτωση που θέλεις να χρησιμοποιήσεις πολλαπλούς αλγόριθμους χωρίς να τους βάλεις όλους μέσα στην SimulationRun μπορείς να χρησιμοποιήσεις ξεχωριστές κλάσεις Algorithm οι οποίες θα κάνουν inhert από κάποια BaseAlgorithm κλάση και θα έχουν πρόσβαση στα collections αλλά δεν θα τα βγάζουν προς τα έξω. Έτσι θα μπορείς να χρησιμοποιήσεις πολλούς διαφορετικούς αλγόριθμους κάνοντας inherit από την BaseAlgorithm χωρίς να χάνεις το πλεονέκτημα του garbage collection.
    • Αν θέλεις το SimulationEvent ή SimulationRun να έχουν κάποια αρχικά δεδομένα μπορείς να τα περάσεις είτε όταν δημιουργείς τις κλάσεις, στον constructor ή σε κάποια factory method. Αν όμως τα δεδομένα αυτά είναι ίδια σε κάθε εκτέλεση, μπορείς να απλοποιήσεις τα πράγματα φτιάχνοντας ένα πρότυπο SimulationRun ή SimulationEvent αντικείμενο με τα αρχικά δεδομένα. Μετά, κάθε φορά που χρειάζεται να δημιουργήσεις ένα νέο αντικείμενο απλά αντιγράφεις το πρότυπο. Αυτό θα βοηθήσει βέβαια μόνο αν η αρχικοποίηση του Run ή Event κοστίζει περισσότερο από την απλή αντιγραφή.

    Γενικά, όταν κάποια λύση φαίνεται υπερβολικά περίπλοκη κατά κανόνα είναι. Συνήθως κάπου υπάρχουν λύσεις ειδικές για το πρόβλημα που θέλεις να λύσεις ... φτάνει να καταφέρεις να προσδιορίσεις ποιό είναι το πρόβλημα. Στην περίπτωση σου το πρόβλημα είναι το Simulation και όχι η προσθαφαίρεση αντικειμένων σε λίστες. Υπάρχουν σχετικά patterns τα οποία πρωτοεμφανίστηκαν με τις ... Simula και SmallTalk.
    Για να συμπληρώσουμε τις Run και Event, ανάλογα με το είδος του Simulation υπάρχουν και EventQueues στις οποίες προστίθενται SimulationEvents για εκτέλεση, είτε περιοδικά είτε μία φορά. Η εκτέλεση ενός περιοδικού event δημιουργεί άλλο ένα στο τέλος του Queue. Κάποια Queues μπορεί να είναι απλά FIFO, άλλα μπορεί να έχουν συγκεκριμένα timeslots έτσι ώστε να είναι δυνατή η δημιουργία ενός event το οποίο θα εκτελεστεί πριν από τα υπόλοιπα προγραμματισμένα event. Events μπορούν να προστεθούν είτε από το πρόγραμμα (εξωτερικά events) είτε από την εκτέλεση ενός άλλου event.

    Με λίγο ψάξιμο για Simulation patterns είμαι σίγουρος ότι θα βρεις και άλλες σχεδιάσεις και παραλλαγές.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems