2016-09-08 2 views
1

In meinem C-Programm habe ich viele Datenstrukturen, die Speicher dynamisch zuweisen. Wenn der Benutzer tut eine der folgenden Aktionen:Bereinigung, wenn der Benutzer mein Programm zum Beenden zwingt?

  • Alt-F4

  • Klicks auf dem X

  • Kraft verlässt über den Task-Manager, etc

dann mein Programm wird ein Speicherleck haben. Wie mache ich eine setzen auf kurze Anfrage Funktion, damit ich meine globalen Variablen aufräumen kann, bevor mein Programm unnatürlich heruntergefahren wird?

Antwort

4

(Ihre Terminologie empfiehlt stark eine Windows-spezifische Anwendung, also habe ich diese Antwort entsprechend geschrieben. Auf anderen modernen Betriebssystemen ist die Terminologie unterschiedlich, aber das Verhalten ist das gleiche, außer für einige eingebettete Umgebungen, aber wenn Sie es wären Kodierung für diejenigen, die Sie diese Frage nicht gestellt hätten.)

Zuerst wird das OS automatisch alle Speicher freigeben, die mit Ihrem Prozess verbunden sind, wenn es beendet wird. Sie müssen sich niemals Gedanken darüber machen, ob der Arbeitsspeicher noch belegt ist.

Zweitens Sie können auf Alt-F4/Fenster schließen Verfügbarkeitsbenachrichtigung. Ich kenne die Details nicht, habe noch nie eine GUI-Anwendung für Windows geschrieben, aber es sollte eine Möglichkeit geben, wie man sie so behandelt, als würde man Beenden in den Menüs der Anwendung wählen; Ihr "Toolkit" könnte dies standardmäßig auch für Sie übernehmen. Die ordnungsgemäße Verwendung dieser Benachrichtigung besteht darin, Dateien auf der Festplatte zu speichern und Netzwerkdialoge sauber zu schließen. (Das Betriebssystem wird auch automatisch schließen alle Datei-Handles und trennen alle Netzwerk-Sockets, aber es wird nicht bündig gespeicherte Änderungen für Sie, noch wird es auf Anwendungsebene Goodbye Nachrichten senden.)

Drittens Sie kann nicht eine Benachrichtigung auf "Kraft quittieren" erhalten, und dies ist von Entwurf, denn es ist die Software entspricht der großen roten Not-Aus-Taste auf einem Industrieroboter - es ist für Situationen, in denen der Prozess weg gerade jetzt, egal Was ist wichtiger als jeder mögliche Datenverlust. Da du nichts dagegen tun kannst, solltest du dir keine Sorgen machen.


Wie in den Kommentaren diskutiert: Ja, bedeutet dies, ist es nicht notwendig Speicher manuell freizugeben vor dem Beenden. In der Tat ist es effizienter wenn Sie nicht, wie diskutiert here und here. Die "allgemeine Weisheit", dass eine manuelle Freigabe erforderlich ist, stammt aus der Frühzeit von Mikrocomputern; (Einige Iterationen von) CP/M und MS-DOS brauchte tatsächlich jede Anwendung, um den Speicher manuell freizugeben; heutzutage ist es eine Instanz von cargo-cult programming.

Das sagte, dort sind einige gute Gründe, Speicher manuell aufzuheben, bevor Sie beenden. Das offensichtlichste ist, dass einige Lecksuche-Tools Sie brauchen, weil sie nicht den Unterschied zwischen "Speicher, den die Anwendung freigegeben haben könnte, wenn sie sich gestört hat" und "Speicher, dass die Anwendung alle gültigen Zeiger verloren hat zu, und kann nicht mehr frei ". Ein weniger offensichtlicher Fall ist, wenn Sie eine Bibliothek schreiben, oder es besteht die Möglichkeit, dass Ihre Anwendung in Zukunft in eine Bibliothek umgewandelt wird. Bibliotheken müssen fähig sein, alle ihre Zuordnungen auf Anforderung von der Anwendung manuell freizugeben, da die Anwendung die Bibliothek während der Lebensdauer eines Prozesses möglicherweise mehrmals einrichten, verwenden und abbauen muss. (Es wird jedoch effizienter, wenn die Anwendung die Bibliothek einmal in ihrer Lebensdauer aufstellt, wiederholt verwendet und dann nicht vor dem Beenden abreißt.)

+0

Das ist wirklich interessant, denn wenn das, was du sagst, wahr ist, dann wurde ich in die Irre geführt. Ich dachte, wenn Sie ein Programm erstellen würden, das nur eine Zeile hätte: 'int main() {long * x = malloc (sizeof (long)); return 0}; 'und wenn Sie das Programm oft genug ausgeführt haben, hat Ihr Computer irgendwann keinen Speicher mehr. Wenn das falsch ist, dann warum alle C-Programme, die ich mir anschaue, den Speicher vor jeder Art von Abschaltung freigeben? Wenn das OS es für mich tut, warum muss ich so viel Zeit damit verbringen, 'free()' für jede globale Variable aufzurufen, der ich Speicher zugewiesen habe? – Hatefiend

+0

@Hatefiend Nicht nur brauchen Sie nicht, es kann viel effizienter sein, wenn Sie nicht tun, wie [hier] (https://stackoverflow.com/questions/231089/freeing-in-an-atexit#242317) und [hier] (https://blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683). Es gibt einen guten Grund, es trotzdem zu tun, aber nur in Debug-Builds: Werkzeuge, die _genuine_ Speicherlecks finden (wo der Prozess, wenn er für immer ausgeführt wird, mehr und mehr Speicher verbrauchen wird), müssen Sie es tun. – zwol

+0

@Hatefiend "Sorgfältig alle Speicher vor dem Verlassen frei" ist ein Fall der [apokryphen fünf Affen und einer Leiter] (http: //www.throwcase.com/2014/12/21/that-five-monkeys-and-a-banana-story-is-müll// effect: es _used_ in den Tagen von CP/M und MS-DOS notwendig sein, und weiterhin zu sein als "best practice" gelehrt, obwohl es nicht mehr nur erforderlich ist, sondern eine _bad_ Praxis. – zwol

2

Sie können eine Funktion beim Beenden mit atexit registrieren. Dies sollte normale Beendigung (durch Rückkehr von main oder ein Anruf an irgendwo im Programm) und Alt + f4 und klicken Sie auf das X auch. Es gibt jedoch nichts, was Ihr Programm tun kann, wenn es getötet wird (erzwingen Sie das Beenden im Task-Manager). Glücklicherweise können und müssen die meisten modernen Betriebssysteme den von Ihrem Programm verwendeten Speicher bereinigen, selbst wenn er aus nicht natürlichen Gründen abstirbt.

Hier ist ein Beispiel für ein Programm mit atexit. Das Programm erstellt (oder schneidet) eine Datei namens atexit.txt. Wenn das Programm normal beendet wird, schreibt es Exited! in die Datei und schließt das Handle.

#include <stdlib.h> 
#include <stdio.h> 

FILE * quitFp; 

void onExit(){ 
    fputs("Exited!", quitFp); 
    fclose(quitFp); 
} 

int main(){ 
    quitFp = fopen("atexit.txt", "w+"); 
    if(!quitFp){ 
     return 1; 
    } 

    atexit(onExit); 

    puts("Press enter to exit"); 

    getchar(); 
    return 0; 
} 

Unter Windows 8.1, kompiliert mit MinGW/GCC funktioniert es für normale return und exit und wenn ich auf das X auf dem Konsolenfenster.

+0

Wird die Funktion, die ich mit 'angeben atexit' wird aufgerufen wenn ich persönlich 'exit (0)' oder 'return 0' nenne? – Hatefiend

+0

@HateFiend, ja es wird – Kninnug

+0

Eine andere Frage, wenn der Benutzer einen Stromausfall hat, seinen Computer herunterfährt oder den Computer herunterfährt, sind Speicherlecks nicht einmal von Bedeutung, oder? Da der RAM beim Booten des Computers geleert wird? – Hatefiend

Verwandte Themen