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

 

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

Όριο 12GB για OOM Exception?

Îåêßíçóå áðü ôï ìÝëïò AlKiS. Τελευταία δημοσίευση από το μέλος Libra Storm στις 25-09-2016, 21:37. Υπάρχουν 3 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  23-09-2016, 02:57 77836

    Όριο 12GB για OOM Exception?

    Καλησπέρα!

     

    Έχω βάλει ένα πρόγραμμα που γράφω σε διάφορους υπολογιστές με διάφορα μεγέθη RAM και παρατηρώ το εξής:

    Όταν βάζω τεράστια επεξεργασία που είναι πολύ memory hungry και το ρυθμίζω έτσι ώστε να χρειάζεται γύρω στα 12GB RAM, σε υπολογιστή με 12GB RAM θα χρησιμοποιήσει όλη τη RAM και θα κάνει τις πράξεις - σε υπολογιστή με πάνω από 12GB RAM θα χρησιμοποιήσει τα 12GB και θα κάνει τις πράξεις.

    Αν το ρυθμίσω ώστε να θέλει έστω και λίγο πάνω από 12GB, τότε σε υπολογιστή με 32GB RAM θα πει "out of memory" μόλις φτάσει στα 12GB.

    Δεδομένου ότι δεν έχει πρόβλημα να πιάσει ολόκληρη τη μνήμη του υπολογιστή (όπως έκανε στο pc με 12GB όταν ήθελε λίγο λιγότερο από 12GB), το γεγονός ότι ακόμα και 32GB RAM να έχει το μηχάνημα, το πρόγραμμα βγάζει OOM στα 12GB με κάνει να φαντάζομαι ότι υπάρχει κάποιο όριο στο πόση RAM μπορεί να δεσμεύσει ένα πρόγραμμα σε VB.NET.

    Ξέρω ότι αυτό δεν ισχύει για όλες τις γλώσσες διότι έχει τρέξει προγράμματα που πιάνουν μόνα τους όχι μόνο τα 32GB αλλά και 10-12GB από paged memory (όπως όταν έκανα topic detection με Latent Dirichlet Allocation μέσω python)

     

    Μπορώ να περάσω αυτό το όριο των 12GB στην vb.net? (εάν υπάρχει βέβαια τέτοιο όριο και δεν είναι κάποιος άλλος λόγος που υπάρχει αυτή η συμπεριφορά)  


    Δημοσίευση στην κατηγορία: , ,
  •  24-09-2016, 15:02 77837 σε απάντηση της 77836

    Απ: Όριο 12GB για OOM Exception?

    Δεν υπάρχει τέτοιο όριο στο .NET οπότε θα πρέπει να κοιτάξεις τί πρόβλημα έχει η ίδια η εφαρμογή. Σχεδόν πάντα το OutOfMemory exception προκαλείται επειδή το πρόγραμμα έχει leaks ή κακή διαχείριση μνήμης και εξαντλεί κάποιο άλλο όριο, όπως π.χ το μέγιστο μέγεθος ενός array είναι 2Β items ή 2GB RAM. Ακόμα και με μικρότερους πίνακες, μπορεί το memory fragmentation να είναι τόσο μεγάλο ώστε να μην μπορείς να βρείς μία συνεχόμενη ελεύθερη περιοχή για να βάλεις πχ. τον πίνακα του 1 GB. Το όριο δεν είναι τυχαίο ούτε περιττό, αν σκεφτείς ότι κάθε πίνακας έναι ένα heap object που πρέπει να το χειριστεί ο garbage collector μέσω του large object heap. Περισσότερα μπορείς να βρεις σε αυτό το SO post, ενώ η εξήγηση και πως αντιμετωπίζεται αναφέρεται εδώ, πχ δημιουργώντας μία BigArray class η οποία κρύβει από κάτω πολλά μικρότερα arrays.

    Μπορείς να αυξήσεις το όριο στα 4Β για πίνακες πολλών διαστάσεων με το  gcAllowVeryLargeObjects setting αλλά πάλι, η κάθε διάσταση έχει το όριο των 2B και 2GB.

    Όπως και να έχει,  το να φορτώσεις τα πάντα στη μνήμη δεν σημαίνει ότι οι υπολογισμοί θα πάνε πιο γρήγορα. Πολλές φορές θα πάνε πιο αργά απλά γιατί οι περισσότεροι αλγόριθμοι υποθέτουν ότι δεν υπάρχει διαφορά μεταξύ ενός πίνακα 10 θέσεων και ενός πίνακα 2Β θέσεων. Στην πραγματικότητα όμως η ταχύτητα επηρεάζεται από την cache των επεξεργαστών, το συγχρονισμό μεταξύ τους για πρόσβαση στην κοινή μνήμη, στο ότι η μνήμη ΔΕΝ είναι κοινή στα μεγάλα μεγέθη, και φυσικά στο χρόνο που χρειάζεται να φορτώσεις αυτές τις 2Β τιμές.

    Αν θέλεις να κάνεις υπολογισμούς σε δις εγγραφές, γιατί να μην τους κάνεις την ίδια ώρα που φορτώνεις το επόμενο πακέτο δεδομένων? Όταν έχεις τόσες εγγραφές ουσιαστικά κάνεις stream processing. Για να αποφύγεις θέματα συγχρονισμού οι επεξεργαστές θα πρέπει να ρουφάνε ένα stream δεδομένων τα οποία θα επεξεργάζονται, όχι να πηγαίνει ο καθένας να τσιμπήσει μία γραμμή εδώ, μία εκεί και να μπλοκάρουν μεταξύ τους. Σε τέτοιες περιπτώσεις  πρέπει να σκεφτείς πως να κάνεις partition τα δεδομένα για να κάνεις παράλληλη επεξεργασία και πως να τροποποιήσεις τους αλγόριθμους για να δουλέψουν σε streams δεδομένων.

    Θα πρότεινα αντί να προσπαθείς με VB.NET να κοιτάξεις κάποια άλλη γλώσσα όπως η C#, F# και η R. Η VB.NET δεν χρησιμοποιείται για computing και έτσι δεν έχει τα πακέτα και βιβλιοθήκες που χρειάζονται ούτε καν τα tutorials για το πως να χρησιμοποιήσεις πχ. TPL ή vectorization. Στο .NET μπορείς πλέον να χρησιμοποιήσεις τις Vector κλάσεις για να επεξεργαστείς vectors των 2 ή 4 τιμών σε μία εντολή, χρησιμοποιώντας τις SSE εντολές του επεξεργαστή, χωρίς καν να χρειαστεί παράλληλη επεξεργασία. Επιπλέον, δεν έχει και κανένα αντίκρυσμα, καθώς είτε επαγγελματικά είτε ακαδημαϊκά, θα πρέπει να μάθεις μία από τις άλλες γλώσσες.

    Η R είναι η πιο δημοφιλής ίσως γλώσσα για data processing και έχει άπειρα πακέτα για οποιοδήποτε μαθηματικό, στατιστικό ή ... βιολογικό πρόβλημα μπορείς να φανταστείς. Το distribution της Revolution Analytics, το οποίο κυκλοφορεί ως Microsoft R μετά την εξαγορά της εταιρείας, χρησιμοποιεί SIMD CPU operations και multi-core τεχνικές για να πετύχει 7+ φορές καλύτερη ταχύτητα από την απλή R σε ένα quad-core. Επίσης, μπορεί να επεξεργαστεί περισσότερα δεδομένα απ' όσα χωράνε στη μνήμη κάνοντας έξυπνο paging





    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  24-09-2016, 15:45 77838 σε απάντηση της 77837

    Απ: Όριο 12GB για OOM Exception?

    Εξαιρετική απάντηση, πλήρης και με πολλές πληροφορίες!

    Ευχαριστώ!!!

     

    Python και R (τώρα και με RevoScaleR) δουλεύω τα τελευταία χρόνια σε πανεπιστημιακά project, οπότε μάλλον θα καταφύγω εκεί.

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

    Μάλλον θα κρατήσω το UI με VB.Net και τα computation θα τα στείλω στην R και θα γυρνάω τα αποτελέσματα στο UI με R.NET


  •  25-09-2016, 21:37 77840 σε απάντηση της 77836

    Απ: Όριο 12GB για OOM Exception?

    Πέρα από την απάντηση του Παναγιώτη, υποθέτω ότι έστω και αν αντιμετωπίσεις το out of memory exception, το μηχάνημα που θα τρέχει την εφαρμογή σου 
    δεν μπορεί να είναι κάποιο "casual" PC αλλά σίγουρα κάποιος server. ΑΝ υπολογίσεις και το πόσοι θα συνδέονται γιά να πάρουν κάποια από αυτά τα δεδομένα θα αντιμετωπίσεις πολύ μεγαλύτερα προβλήματα.

    Από το framework 4.5 και μετά σε 64 bit build υπάρχει μεν το όριο σε array size των 2 giga κλπ αλλά δεν υπάρχουν τέτοιοι περιορισμοί χρησιμοποιώντας την παράμετρο gcallowverylargeobjects στο configuration file 
    που είχα αναφέρει στο προηγούμενο post που έκανες.

    Remarks

    Using this element in your application configuration file enables arrays that are larger than 2 GB in size, but does not change other limits on object size or array size:
    The maximum number of elements in an array is UInt32.MaxValue.
    The maximum index in any single dimension is 2,147,483,591 (0x7FFFFFC7) for byte arrays and arrays of single-byte structures, and 2,146,435,071 (0X7FEFFFFF) for other types.
    The maximum size for strings and other non-array objects is unchanged.

    Παρόλα αυτά  η διαχείρηση μνήμης σε .net με τόσο μεγάλο όγκο δεδομένων από τον Garbage Collector θα σε κάνει να χτυπάς το κεφάλι σου αφού 
    ο GC δυστυχώς δεν έχει σχεδιαστεί από την αρχή του .NET γιά να αντιμετωπίσει τέτοια προβλήματα.

    Στο post https://blogs.msdn.microsoft.com/joshwil/2005/08/10/bigarrayt-getting-around-the-2gb-array-size-limit/
    ο κώδικας που του BigArray δεν δουλεύει αλλά τον άλλαξα γιά να μπορείς να τον χρησιμοποιήσεις, χωρίς περιορισμούς framework ή 64 bit
    η ακόμα καλύτερα να τον τον επεκτείνεις σε BigList<T>.
     
    Σπάει απλά το size του array σε blocks και στο τελευταίο block βάζει τα elements που περρισεύουν (αν υπάρχουν)
    χρησιμοποιώντας την elementsInLastBlock και μετά με τον indexer κάνει partition το κάθε element στην θέση που πρέπει.

    Επιμένω στην χρήση Database γιά τέτοια σενάρια αφού ο SQL Server δεν είναι γραμμένος σε .NET και
    δεν υπόκειται σε τέτοιους περιορισμούς ή φτιάξε ένα dll σε C++/CLI ή όπως αλλιώς λέγεται τώρα γιά να κάνεις την δουλεία σου.

        /// <summary>
        /// https://blogs.msdn.microsoft.com/joshwil/2005/08/10/bigarrayt-getting-around-the-2gb-array-size-limit/
        /// </summary>
        /// <typeparam name="T"></typeparam>
        class BigArray<T>
        {
            // These need to be const so that the getter/setter get inlined by the JIT into 
            // calling methods just like with a real array to have any chance of meeting our 
            // performance goals.
            //
            // BLOCK_SIZE must be a power of 2, and we want it to be big enough that we allocate
            // blocks in the large object heap so that they don’t move.
            internal const int BLOCK_SIZE = 524288; // 2 ^ 19
            internal const int BLOCK_SIZE_LOG2 = 19; // Raise 2 in 19th power to get Block Size.

            // Don’t use a multi-dimensional array here because then we can’t right size the last
            // block and we have to do range checking on our own and since there will then be 
            // exception throwing in our code there is a good chance that the JIT won’t inline.
            T[][] _elements;
            ulong _length;

            // maximum BigArray size = BLOCK_SIZE * Int.MaxValue
            public BigArray(ulong size)
            {
                int numBlocks = (int)(size / BLOCK_SIZE);
                int elementsInLastBlock = BLOCK_SIZE;

                int diff = (int)(size - (ulong)(numBlocks * BLOCK_SIZE));

                if (diff > 0)
                {
                    elementsInLastBlock = diff;
                    numBlocks += 1;
                }

                _length = size;
                _elements = new T[numBlocks][];

                // do not assign BLOCK_SIZE to last element (that's why we loop until (numBlocks -1))
                // instead assign it after the for loop with
                // elementsInLastBlock value.
                for (int i = 0; i < (numBlocks -1); i++)
                    _elementsIdea = new T[BLOCK_SIZE];

                // Since Elements is a jagged array, 
                // the last element can be smaller than BLOCK_SIZE.
                _elements[numBlocks - 1] = new T[elementsInLastBlock];
            }

            public ulong Length { get { return _length; } }

            public T this[ulong elementNumber]
            {
                // these must be _very_ simple in order to ensure that they get inlined into
                // their caller 
                get
                {
                    int blockNum = (int)(elementNumber >> BLOCK_SIZE_LOG2);
                    int elementNumberInBlock = (int)(elementNumber & (BLOCK_SIZE - 1));
                    return _elements[blockNum][elementNumberInBlock];
                }
                set
                {
                    int blockNum = (int)(elementNumber >> BLOCK_SIZE_LOG2);
                    int elementNumberInBlock = (int)(elementNumber & (BLOCK_SIZE - 1));
                    _elements[blockNum][elementNumberInBlock] = value;
                }
            }
        }
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems