Υπάρχει διαφορά απόδοσης μεταξύ της κατανομής της μνήμης σε χρόνο εκτέλεσης και του χρόνου μεταγλώττισης στη γλώσσα προγραμματισμού C;


Απάντηση 1:

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

Με αυτόν τον τρόπο, η "στατική κατανομή της μνήμης" γίνεται θέμα "αφήνοντας κατάλληλες τρύπες" στο εκτελέσιμο (όλες συρρικνωμένες σε μια "ενότητα" της αρχικής μνήμης και σε μια "rss" ενότητα της μη αρχικοποιημένης μνήμης) της χαρτογράφησης του εκτελέσιμου στη μνήμη κατά το φορτίο του προγράμματος χωρίς καμία αξιοσημείωτη επιβάρυνση κατά το χρόνο εκτέλεσης.

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

Ρωτήσατε: Υπάρχει διαφορά απόδοσης μεταξύ της κατανομής της μνήμης σε χρόνο εκτέλεσης και του χρόνου μεταγλώττισης στη γλώσσα προγραμματισμού C;


Απάντηση 2:

Ναι, είναι προφανώς ταχύτερη για να το κάνετε κατά το χρόνο κατάρτισης αλλά αυτό εξαρτάται. Βασικά αυτό που κάνετε με το χρόνο μεταγλώττισης είναι η προεπεξεργασία του τι θα γίνει κατά το χρόνο εκτέλεσης.

Αυτό είναι ένα είδος κοινών σε συστήματα χαμηλού επιπέδου, όπου το malloc είναι κάτι σαν να μπερδεύεται. Το Malloc σπαταλά τους πόρους και τους κύκλους, οπότε αν σχεδιάζετε αυτό κατά το χρόνο σύνταξης, μπορείτε να αποφύγετε αυτό το γενικό κόστος.

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


Απάντηση 3:

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

Έτσι

compile time:

static char bigstring [5000];

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

runtime:

char * pBigString = malloc (5000).

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

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


Απάντηση 4:

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

Η μνήμη είναι μνήμη. Είναι πιο γρήγορη από ό, τι διαβάζει και γράφει ο δίσκος, μεταφορές USB κλπ. Η κύρια μνήμη είναι παγετώδης αργή σε σύγκριση με τη μνήμη cache της CPU και επίσης με την μνήμη βίντεο στην κάρτα γραφικών.

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

Η μνήμη που διατίθεται κατά τη διάρκεια εκτέλεσης (δυναμική μνήμη, μνήμη σωρού) θα κατανεμηθεί στην ίδια κύρια μνήμη με οποιαδήποτε άλλη, αλλά δεν μπορεί να βελτιστοποιηθεί πολύ καλά από τον μεταγλωττιστή. Επομένως, μπορεί να είναι 50/50 αν η μνήμη σωρού σας θα διαρκέσει μερικά χιλιοστά του δευτερολέπτου ή μερικές εκατοντάδες χιλιοστά του δευτερολέπτου για να διαθέσει και αν θα ταιριάζει με όλα στην προσωρινή μνήμη CPU και θα είναι σε μια ωραία σελίδα μνήμης ή θα διαδοθεί σε πολλές σελίδες μνήμης.

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

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

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

Όλα αυτά γίνονται συνήθως κάτω από το επίπεδο στο οποίο ο προγραμματιστής το βλέπει ή έχει τον έλεγχο. Μέχρι στιγμής το πιο αργό μέρος της μνήμης είναι I / O από συσκευές. Έτσι, συνήθως η καλύτερη ταχύτητα που μπορείτε να έχετε εάν αντιμετωπίζετε συμφόρηση I / O με συσκευές είναι να αντιστοιχίσετε τη συσκευή σε ένα ΑΡΧΕΙΟ με μνήμη που έχει αντιστοιχιστεί με ένα buffer και να αποφορτώσετε το I / O σε ένα ξεχωριστό νήμα.

Ορισμένα λειτουργικά συστήματα σας δίνουν ακόμη ένα σύστημα αρχείων με μνήμη που ήδη μπορείτε να χρησιμοποιήσετε ακριβώς όπως ένα συνηθισμένο αρχείο ή κατάλογο! (Το Linux έχει τον / var / run / shm ("κοινόχρηστο mem") κατάλογο όπου μπορείτε να το κάνετε αυτό - πολύ γρήγορα).