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

 

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

Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

Îåêßíçóå áðü ôï ìÝëïò fanisg. Τελευταία δημοσίευση από το μέλος Παναγιώτης Καναβός στις 09-02-2011, 09:33. Υπάρχουν 30 απαντήσεις.
Σελίδα 1 από 3 (31 εγγραφές)   1 2 3 >
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  08-02-2011, 10:03 63084

    Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

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

    Επί της ουσίας: 
    Α) Συντάσσω κάποιες κλάσεις σε VB.NET (επεξεργασία χωρικών δεδομένων), οι οποίες δουλεύουν άψογα αλλά... δεν φεύγουν ποτέ από τη μνήμη.
    Ως αποτέλεσμα όταν π.χ. προσπαθώ να επεξεργαστώ* ένα collection από 800.000 στιγμιότυπα μιας κλάσης, η μνήμη διαρκώς αυξάνει ώσπου, το γνωστό exception! 
    Υπάρχει ένα αντιληπτό πρόβλημα με τα references. Πιθανώς να μην τα συμμαζεύει ο GC διότι διατηρούν references στη μνήμη. 
    ΟΜΩΣ περνώντας ένα x στιγμιότυπο σε μια ρουτίνα ως όρισμα, όπως και αν δηλωθεί, χρησιμοποιείται byRef και όχι byVal και οι τιμές τους είναι δυστυχώς αλλοιώσιμες. Η έξοδος από τη ρουτίνα δεν τα καθαρίζει. Δοκίμασα να τα "αντιγράφω" όπου χρειάζεται με χρήση του Interface Icloneable, αυτό όμως έχει ως συνέπεια το επιπλέον "φούσκωμα" της μνήμης και τον ερχομό του γλυκύτατου exception μια ώρα αρχύτερα.
    Πως μπορώ να "περιορίσω" τα περιττά στιγμιότυπα κλάσεων; Πως μπορώ να καθαρίσω τις local δηλώσεις; Υποτίθεται ότι μη χρησιμοποιώντας unmanaged resources δεν θα ήταν αναγκαία η χρήση του Dispose. Ωστόσο, δοκιμάστηκε, απέτυχε, αφαιρέθηκε.

    Β) Ως συνέχεια του παραπάνω, όταν τελικώς λαμβάνω τα αποτελέσματα μέσα στην εφαρμογή μου, (και είναι μετρημένα και "ζυγισμένα") γιατί η κατανάλωση μνήμης δεν πέφτει; Είναι σαν να κουβαλάω το σύνολο των κλάσεων επί x στιγμιότυπα. Η δε αποθήκευση ενός collection δεδομένων με serialization φουσκώνει επιπλέον τη μνήμη και υποβαθμίζει απείρως την ταχύτητα.

    Μη δουλεύοντας μόνο με ένα τύπο αντικειμένων αλλά με πολλά εμπλεκόμενα λόγω της δομής τους, δεν μπόρεσα να χρησιμοποιήσω το Using και δεν ξέρω καν αν θα βοηθούσε. (Στην αποθήκευση ΔΕΝ βοηθάει). Προερχόμενος δε από το χώρο του Visual Studio 6 μου φαίνονται "περίεργα" όλα αυτά. Δεν είχα ποτέ πρόβλημα διαχείρισης μνήμης παλαιότερα.

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

    Συγνώμη αν σας κούρασα, ευελπιστώ στην όποια βοήθεια.
  •  08-02-2011, 10:14 63086 σε απάντηση της 63084

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Quick n Dirty: 

    GC.Collect

    Το δοκίμασες;

    "When the darkness rises up from inside - that is normal.
    It's when you reach down to pull it up - that the noxious warnings sound."
    Tuzak, Farscape
  •  08-02-2011, 10:17 63087 σε απάντηση της 63086

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Αν και μου φαίνεται ότι το πρόβλημα είναι αλγοριθμικό και όχι τεχνικό...
    "When the darkness rises up from inside - that is normal.
    It's when you reach down to pull it up - that the noxious warnings sound."
    Tuzak, Farscape
  •  08-02-2011, 10:47 63088 σε απάντηση της 63087

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Ναι, φυσικά, το θέμα είναι ότι ο Collector μάλλον τα αγνοεί. Πέραν τούτου κάθε collect καθυστερεί τα iterations κατά 1 sec, συνεπώς η επιβεβλημένη χρήση του είναι απαράδεκτη.
    Αλγοριθμικό πρόβλημα βλέπω και εγώ, το που the h_ll είναι δεν βλέπω!
  •  08-02-2011, 10:57 63089 σε απάντηση της 63088

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Βασικά, χρειάζεται όντως να έχεις 800.000 instances στη μνήμη; Δεν μπορείς να κάνεις την ίδια δουλειά με τη χρήση πχ μίας ΒΔ;

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

    To collect δεν είναι για χόρταση πάντως, πρέπει να το φωνάζεις ... κατά καιρούς! Δεν είναι για να το βάζεις κάθε φορά που κάνεις ένα object = null. 

    Το IDisposable γιατί δεν σου κάνει;

    "When the darkness rises up from inside - that is normal.
    It's when you reach down to pull it up - that the noxious warnings sound."
    Tuzak, Farscape
  •  08-02-2011, 11:00 63090 σε απάντηση της 63089

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Αν και μπορεί να μην κάνει apply στην περίπτωσή σου, έχεις δοκιμάσει κάποια παραλλαγή του Flyweight pattern; (και εδώ για άλλο ένα tutorial). Το αναφέρω μόνο και μόνο γιατί μου "μυρίζει" ότι θα μπορούσες ίσως να επωφεληθείς από κάποια τέτοια σχεδίαση (όχι απαραίτητα αυτή που υπαγορεύει το pattern, αλλά κάτι που θα μειώσει τον αριθμό των instances που έχεις in-memory).


    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  08-02-2011, 11:25 63092 σε απάντηση της 63089

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    @dimos.homatas:
    Η DB δεν μου κάνει. Τα δεδομένα είναι συνδεδεμένα χωρικά και παράγουν περισσότερο σύνθετες ενότητες. Σε μεγάλο βαθμό χρειάζομαι ακόμα και τα προγονικά τους στοιχεία για να κατευθύνω την αναζήτηση ώστε να επιτύχω τις n(logn) χρονικές απαιτήσεις. 
    Το IDisposable εμένα μου κάνει, ΑΥΤΟ δεν θέλει να λειτουργήσει σωστά!

    @cap:
    Δεν μπορώ να πω ότι κατάλαβα τη λογική του Flyweight... υπάρχει τρόπος να περάσω στιγμιότυπα ως ορίσματα byval? Αυτό ίσως να μου έλυνε ένα μέρος του προβλήματος..
  •  08-02-2011, 11:53 63093 σε απάντηση της 63084

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Νομίζω ότι το κλειδί του μυστηρίου βρίσκεται σε αυτή σου την φράση.

     

    Μη δουλεύοντας μόνο με ένα τύπο αντικειμένων αλλά με πολλά εμπλεκόμενα λόγω της δομής τους, δεν μπόρεσα να χρησιμοποιήσω το Using και δεν ξέρω καν αν θα βοηθούσε.

     

    Ίσως κάνω λάθος, αλλά από ότι αντιλαμβάνομαι από το ένα αντικείμενο κάνεις reference σε άλλα (ένα ή περισσότερα) αντικείμενα της λίστας. Οπότε όπως είπες και εσύ είναι πρόβλημα με τα references.

    Αντιλαμβάνομαι λοιπόν ότι έχεις μια λίστα από spaghetti objects (κατά αντιστοιχία του spaghetti code Smile ) Αφαιρώντας ένα αντικείμενο από την λίστα, αυτό δεν πεθαίνει γιατί το κρατάει ζωντανό κάποιο άλλο.

     

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

     

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

     

    Ελπίζω να έπιασες την λογική μου. Δεν με ενθουσιάζει σαν λύση αλλά ίσως σε βοηθήσει να καταλάβεις τι φταίει. Είσαι σίγουρος ότι πρέπει να φύγει από την μνήμη; Μήπως τα άλλα αντικείμενα που το κάνουν reference το χρειάζονται ακόμα; Αν το χρειάζονται ακόμη, τότε θα πάρεις λάθος αποτελέσματα στους υπολογισμούς σου. Μπορεί απλά να χτύπησες ταβάνι και σε αυτή την περίπτωση να πρέπει να αλλάξεις προσέγγιση στο πρόβλημα.

  •  08-02-2011, 11:57 63094 σε απάντηση της 63084

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    fanisg:
    Β) Ως συνέχεια του παραπάνω, όταν τελικώς λαμβάνω τα αποτελέσματα μέσα στην εφαρμογή μου, (και είναι μετρημένα και "ζυγισμένα") γιατί η κατανάλωση μνήμης δεν πέφτει; Είναι σαν να κουβαλάω το σύνολο των κλάσεων επί x στιγμιότυπα. Η δε αποθήκευση ενός collection δεδομένων με serialization φουσκώνει επιπλέον τη μνήμη και υποβαθμίζει απείρως την ταχύτητα.

    Επειδή τώρα το είδα αυτό, μήπως όταν λαμβάνεις τα αποτελέσματα στην εφαρμογή σου, διατηρείς references στα αρχικά σου instances, τα οποία, όπως κατάλαβα από τα συμφραζόμενα, διατηρούν references σε άλλα instances και ούτω καθ'εξής; Υποψιάζομαι οτι ο garbage collector συνεχίζει να βλέπει references που χρησιμοποιούνται και γι'αυτό δεν "θέλει" να σου καθαρίσει κάτι. Ολα αυτά βέβαια είναι εικασίες μου. :)

    Μήπως να αντέγραφες (για το presentation) τα αποτελέσματα σε κάποια άλλη δομή, ελευθερώνοντας τα references τα αρχικά instances; (Εκτός αν το κάνεις ήδη αυτό, οπότε εκεί σηκώνω τα χέρια ψηλά).


    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  08-02-2011, 12:01 63095 σε απάντηση της 63092

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    fanisg:
    @cap:
    Δεν μπορώ να πω ότι κατάλαβα τη λογική του Flyweight... υπάρχει τρόπος να περάσω στιγμιότυπα ως ορίσματα byval? Αυτό ίσως να μου έλυνε ένα μέρος του προβλήματος..
    Το έδωσα απλά σαν point of reference (του στυλ "υπάρχει και αυτό")... Ούτε εγώ είμαι σίγουρος για τον τρόπο που θα μπορούσες να το χρησιμοποιήσεις γιατί δεν ξέρω τα internals της εφαρμογής σου. Οπως είπα, ίσως να μην κανει καθόλου apply.

    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  08-02-2011, 12:15 63096 σε απάντηση της 63095

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Αν φαίνεται ότι δεν ελευθερώνεται η μνήμη, σημαίνει ότι υπάρχουν ακόμα references στις κλάσεις - σε κάποια λίστα ή επειδή έχουν σχέσεις μεταξύ τους και έχει παραμείνει reference σε ένα από αυτά. Το πρόβλημα θα πρέπει να εντοπιστεί στην εφαρμογή και όχι στον garbage collector, ο οποίος εξάλλου δεν θα μπορέσει να ελευθερώσει μνήμη η οποία χρησιμοποιείται ακόμα. 

    Διαβάζοντας το αρχικό post υποψιάζομαι ότι έχει γίνει μπέρδεμα στο πως χειρίζεται τη μνήμη το .NET (δεν διαφέρει μεταξύ VB.NET και C#) και πως δούλευε η VB6. Το ByVal, ByRef δεν έχουν νόημα όταν μιλάμε για reference τύπους, ούτε καθαρίζονται αμέσως μόλις βγεις από μία ρουτίνα, ακόμα και αν έχουν οριστεί μέσα σε ένα function. Ο Garbage Collector καλείται περιοδικά για να καθαρίσει όσα instances δεν έχουν πλέον references. 

    Θα πρότεινα να καθαρίσεις τον κώδικα σου από κάθε προσπάθεια να "διορθώσεις" το .NET και απλά να περνάς τα instances χωρίς τροποποιήσεις, κλωνοποιήσεις και απόπειρες διαγραφής. Αν θέλεις να φεύγουν από τη μνήμη, φρόντισε απλά να μην μένουν references. Εξάλλου είναι bug να θέλεις να διαγραφούν instances στα οποία υπάρχουν ακόμα references - τί θα γίνει όταν ο κώδικας σου προσπαθήσει να χρησιμοποιήσει αυτά τα references? Από τη στιγμή που δεν ξέρεις που έχουν ξεφύγει αυτά τα references, υποψιάζομαι ότι θα χρειάζεται και ένα γενικό νοικοκύρεμα του κώδικα.

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  08-02-2011, 12:18 63097 σε απάντηση της 63095

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Βασικά όλα όσα μου είπατε είναι σωστά. Αυτό που δεν καταλαβαίνω είναι το εξής: Το reference αν και εφόσον υπάρχει (έστω X φορές), δεν δείχνει ένα και μόνο ένα αντικείμενο στη μνήμη; Αν ναι, τότε όταν αρχικοποιώ την επεξεργασία πασσάροντας ένα set π.χ. Ν  of(3Δ σημεία), αυτά δεν θα έπρεπε να παραμένουν Ν; Όταν τα βρίσκω Ν*a στη μνήμη (με χρήση memory profiler), πού μπορεί να οφείλεται αυτό; 

    p.s. χωρίς κλονισμό (μόνο νευρικό)
  •  08-02-2011, 12:24 63098 σε απάντηση της 63097

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Χαζές ερωτήσεις:

    Μήπως:

    1. Κανεις new
    2. Κάνεις copy/clone 
    3. Φτιάχνεις πράγματα από factory

    σε κάποιο σημείο και το έχεις "ξεχάσει"; 

    Αν οχι, πές μας λίγο τι members περιέχει κάθε instance που φτιάχνεις. Εχει value types; Εχει references σε unmanaged resources; Μήπως κάποια μέθοδος στην πορεία κάνει instantiate κάτι (managed ή unmanaged); 



    Σωτήρης Φιλιππίδης

    DotSee Web Services

    View Sotiris Filippidis's profile on LinkedIn

    DotNetNuke them!
  •  08-02-2011, 12:28 63099 σε απάντηση της 63095

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    Γιά να μετριάσεις το πρόβλημα σου μπορείς να δοκιμάσεις τα εξής.

    Δοκίμασε structures (value types) αν οπωσδήποτε θέλεις να παίρνεις κόπιες των αντικειμένων σου. Πρόσεχε το stack σου όμως

    Βγάζε τα handles των events (αν έχεις).

    μην ξαναγεμίζεις ένα array, collection με δεδομένα χωρίς πρώτα να κάνεις nothing τα προηγούμενα. 

    όταν περνάς ένα class byval η διεύθυνση μνήμης του δεν αλλάζει (είναι κόπια). Όταν το περνάς byref (δείκτη σε δείκτη) μπορείς να την αλλάξεις (πχ να το κάνεις nothing).

    Εγώ προσπαθώ να γράφω σαν να μήν υπάρχει Garbage collector. Με βοήθησε αρκετά.

  •  08-02-2011, 12:30 63100 σε απάντηση της 63098

    Απ: Πρόβλημα με την απελευθέρωση μνήμης στη VB.NET

    1. New γίνεται σε κάθε αρχικοποίηση στιγμιοτύπου (υποχρεωτικά;)
    2. Το Clone το χρησιμοποιώ συνειδητά μόνο σε ορισμένες περιπτώσεις, όπου ακολουθεί με το πέρας εκκαθάριση και =nothing.
    3. Απ'όσο γνωρίζω όχι.

    Δεν χρησιμοποιώ καθόλου unmanaged resources, com objects, dll & activex περασμένων τεχνολογιών. Αλλά πλέον δεν είμαι σίγουρος αν κάνω καλά...!

    Εντάξει, έχω αρχίσει να αισθάνομαι άχρηστος. Ως νέος στη .ΝΕΤ προσπάθησα ότι μπορούσα να φανταστώ 2 μήνες τώρα. Δεν είχα kick start μέσω βοηθημάτων δυστυχώς και ίσως να παρερμήνευσα κάπου τις δομές λειτουργίας της .NET

    Πάμε από την αρχή: 
    1. Να χρησιμοποιώ απλή εκχώρηση (=) ή clone;
    2. Τα references στο ίδιο αντικείμενο επιβαρύνουν τη μνήμη αθροιστικά;
     
Σελίδα 1 από 3 (31 εγγραφές)   1 2 3 >
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems