In che modo la JVM gestisce un'eccezione generata dal metodo principale?


10

Comprendo le eccezioni, le lancio, la gestione e la propagazione a un metodo inferiore nello stack di chiamate (ad es throws.).

Quello che non capisco è questo:

public static void main(String[] args) throws Exception {
    ...
}

Ora, suppongo che nel caso in cui venga lanciato mainun Exception, JVM lo gestisca (giusto?). In tal caso, la mia domanda è:

In che modo la JVM gestisce le eccezioni generate main? Che cosa fa?

Risposte:


19

Potresti pensare che il public static void mainmetodo in Java o la mainfunzione in C sia il vero punto di ingresso del tuo programma, ma non lo è. Tutte le lingue di alto livello (incluso C) hanno un runtime linguistico che inizializza il programma e quindi trasferisce il flusso di controllo al punto di ingresso. Nel caso di Java, l'inizializzazione includerà:

  • impostazione di JVM
  • caricamento delle classi richieste
  • esecuzione di blocchi di inizializzatori statici. Questo può eseguire il codice definito dall'utente prima che mainvenga invocato. Questi blocchi non dovrebbero generare eccezioni.

Esistono diversi modi per implementare la gestione delle eccezioni, ma ai fini di questa domanda, tutti possono essere visti come una scatola nera. La cosa importante, tuttavia, è che il runtime della lingua deve sempre fornire un gestore di eccezioni più esterno che intercetta tutte le eccezioni non rilevate dal codice utente. Questo gestore di eccezioni in genere stampa una traccia dello stack, arresta il programma in modo ordinato ed esce con un codice di errore. La corretta chiusura del programma include la distruzione del grafico a oggetti, l'invocazione di finalizzatori e la liberazione di risorse quali memoria, handle di file o connessioni di rete.

A scopo illustrativo, è possibile immaginare il runtime che avvolge tutto il codice in un gigantesco try-catch che assomiglia

try {
    loadClasses();
    runInitializers();
    main(argv);
    System.exit(0);
} catch (Throwable e) {
    e.printStackTrace();
    System.exit(-1);
}

tranne per il fatto che non è necessario che una lingua esegua effettivamente codice come questo. La stessa semantica può essere implementata nel codice per throw(o equivalente) che cerca il primo gestore di eccezioni applicabile.


9

Tutto il codice Java viene eseguito nel contesto di un thread . JavaDoc collegato spiega la gestione degli errori e i criteri di uscita, ma qui è l'essenziale:

  • La JVM si gira da sola e prepara l'ambiente di esecuzione.
  • La JVM crea un thread che eseguirà il main()metodo utilizzando qualsiasi parametro della riga di comando applicabile.
  • JVM imposta un gestore eccezioni non rilevate predefinito che stampa l'eccezione sull'errore standard e termina.
  • La JVM esegue il thread.

Nel caso di un'eccezione non rilevata, il programma muore effettivamente per il terzo elemento sopra. Questo comportamento è ulteriormente specificato nelle Specifiche del linguaggio Java, Sezione 11.3


informazioni addizionali

Altri hanno menzionato blocchi statici e come vengono eseguiti in precedenza main(). Tuttavia, questo richiede una spiegazione un po 'più per capire correttamente.

Quando si carica una classe, il caricatore di classe deve inizializzare tutto lo static finalstato ed eseguire tutti i staticblocchi prima di poter utilizzare la classe, per includere istanze della classe (a parte: creare una classe Java in cui una costante di classe viene inizializzata in un blocco statico dopo aver creato un istanza della classe e il costruttore fa riferimento alla costante. Boom!). Tuttavia, tutto ciò accade nella logica del caricatore di classi prima che qualsiasi codice possa fare riferimento alla classe . Inoltre, la classe viene caricata in qualsiasi thread a cui fa riferimento la classe.

Ciò significa che se la classe contenente fa main()riferimento a un'altra classe (ad es. Costante di classe), allora quella classe deve essere caricata prima di essere main()eseguita per includere i suoi blocchi statici. Altrimenti, i blocchi statici vengono eseguiti come sopra. Se la classe non riesce a caricarsi, anche la classe contenente main()non si caricherà e il programma terminerà.

Un'altra FYI: i blocchi statici possono lanciare. Errorsvengono gettati così come sono. Exceptionssono vietati (errore di compilazione). RuntimeExceptionssono racchiusi in ExceptionInInitializerError . Questi sono gestiti dal gestore delle eccezioni non rilevate, che generalmente ucciderà il thread o l'applicazione (thread principale) a meno che non si avvolga con attenzione il riferimento di classe (e il caricamento) in un try- catch.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.