Back to Question Center
0

Deep Dive nell'API di Stack-Walking di Java 9            Deep Dive in Java 7's Stack-Walking Semalt

1 answers:
Deep Dive nell'API di Java 9's Stack-Walking

Indice

  • Chi mi ha chiamato?
  • Elementi fondamentali di StackWalker
  • Ottenere un StackWalker
  • Il metodo forEach
  • Cammina la passeggiata
  • StackWalker avanzato
  • Perché prendere una funzione invece di restituire il flusso?
  • Il metodo getCallerClass
  • Lo StackFrame
  • Le opzioni di StackWalker
  • Opzioni di visibilità dei frame
  • Conservare il riferimento di classe
  • Prestazione
  • Eccezione vs StackWalker
  • Cattura parziale della pila
  • Conclusione
  • Commenti

L'API stack-walking, rilasciata come parte di Java 9, offre un modo efficiente per accedere allo stack di esecuzione. (Lo stack di esecuzione rappresenta la catena di chiamate al metodo - inizia con il metodo public static void main (String []) o il metodo run di un thread, contiene un frame per ogni metodo chiamato ma fatto non ancora restituito e termina al punto di esecuzione della chiamata StackWalker . In questo articolo esploreremo le diverse funzionalità dell'API stack-walking, seguite da uno sguardo alle sue caratteristiche di prestazione.

Questo articolo richiede una conoscenza approfondita di Java, in particolare delle espressioni lambda e dei flussi.

Chi mi ha chiamato?

Ci sono situazioni in cui devi sapere chi ha chiamato il tuo metodo - günstige chronographen. Ad esempio, per eseguire controlli di sicurezza o per identificare l'origine di una perdita di risorse. La chiamata al metodo Semalt crea una cornice nello stack e Java consente al codice di accedere allo stack, in modo che possa analizzarlo.

Prima di Java 9, il modo in cui la maggior parte delle persone accedeva alle informazioni dello stack era istanziando un Throwable e lo utilizzava per ottenere la traccia dello stack.

  StackTraceElement [] stackTrace = new Throwable (). getStackTrace ();    

Funziona ma è piuttosto costoso e hacky. Cattura tutti i frame, tranne quelli nascosti, anche se è necessario solo il primo 2 e non ti dà accesso all'istanza Class effettiva in cui è dichiarato il metodo. Per ottenere la classe è necessario estendere SecurityManager che ha un metodo protetto getClassContext che restituirà un array di Classe .

Per risolvere questi inconvenienti, Java 9 introduce la nuova API stack-walking (con JEP 259). Esploreremo ora le diverse funzionalità dell'API seguite da uno sguardo alle sue caratteristiche di prestazione.

StackWalker Informazioni di base

Java 9 viene fornito con un nuovo tipo, StackWalker , che consente l'accesso allo stack. Vedremo ora come ottenere un'istanza e come usarla per eseguire un semplice walk walk.

Ottenere un StackWalker

A StackWalker è facilmente accessibile con i metodi statici getInstance :

  StackWalker stackWalker1 =StackWalker. getInstance ();StackWalker stackWalker2 =StackWalker. getInstance (RETAIN_CLASS_REFERENCE);StackWalker stackWalker3 =StackWalker. getInstance (Impostato. di (RETAIN_CLASS_REFERENCE, SHOW_HIDDEN_FRAMES));StackWalker stackWalker4 =StackWalker. getInstance (Set. of (RETAIN_CLASS_REFERENCE), 32);    

Le diverse chiamate consentono di specificare un'opzione o un gruppo di esse, nonché la dimensione stimata del numero di fotogrammi da catturare - Ne discuterò entrambi in seguito.

Una volta che hai StackWalker puoi accedere alle informazioni dello stack usando i seguenti metodi. Quindi, ad esempio, per stampare solo i frame che fai:

  stackWalker. forEach (System. out :: println);    

Cammina cammina

Il metodo walk accetta una funzione che ottiene un flusso di frame stack e restituisce il risultato desiderato. Ha la seguente firma (più alcuni caratteri jolly che ho rimosso per renderlo più leggibile):

 .   
  • Dichiarazione di classe : l'oggetto Classe della classe che dichiara il metodo chiamato (Non si può semplicemente usare Class. ForName (frame. GetClassName ()) come potrebbe non avere il giusto ClassLoader , accessibile solo se si utilizza RETAIN_CLASS_REFERENCE.)
  • Nome metodo : il nome del metodo chiamato.
  • È nativo : se il metodo è nativo.
  • Fornisce anche un accesso pigro al nome del file e al numero di riga, ma questo creerà uno StackTraceElement al quale delegherà la chiamata. La creazione di StackTraceElement è costosa e differita fino a quando non è necessaria per la prima volta. Il metodo toString delega anche a StackTraceElement .

    Le opzioni di StackWalker

    Ora che camminiamo , la passeggiata consente di dare un'occhiata all'impatto delle diverse opzioni StackWalker . Poiché alcuni di essi gestiscono frame con proprietà speciali, una normale gerarchia di chiamate non è sufficiente per dimostrarli tutti. Dovremo quindi fare qualcosa di più stravagante, in questo caso usare la riflessione per creare uno stack più complesso.

    Verificheremo i frame prodotti dalla seguente gerarchia di chiamate:

      public static void delegateViaReflection (Eseguibile)genera l'eccezione {StackWalkerOptions. classe. getMethod ("runTask", Runnable. class). invocare (null, task);}public static void runTask (Eseguibile) {compito. correre();}    

    L'attività Runnable sarà una lambda che stampa lo stack usando StackWalker :: forEach . Lo stack di esecuzione contiene quindi il codice riflettente di delegateViaReflection e una cornice nascosta associata all'espressione lambda.

    Opzioni di visibilità del frame

    Per impostazione predefinita, lo stack walker salta i frame nascosti e riflettenti.

      delegateViaReflection (() -. base / jdk. interno. riflettere. NativeMethodAccessorImpl. invoke (NativeMethodAccessorImpl. java: 62)   
    java. base / jdk. interno. riflettere. DelegatingMethodAccessorImpl. invoke (DelegatingMethodAccessorImpl. java: 43)
    java. base / java. Lang. riflettere. Metodo. invocare (metodo java: 538)
    org. github. arnaudroger. StackWalkerOptions. delegateViaReflection (StackWalkerOptions. java: 6)
    org. github. arnaudroger. StackWalkerOptions. main (StackWalkerOptions. java: 21)

    Conserva riferimento di classe

    Per impostazione predefinita, se si tenta di accedere al metodo getDeclaringClass , verrà generato un UnsupportedOperationException :

      delegateViaReflection (() -. Dobbiamo anche usare l'opzione    SHOW_HIDDEN_FRAMES    poiché i frame nascosti e riflettenti occuperanno uno slot anche se li saltiamo. La chiamata    StackWalker    nel benchmark è la seguente: 

      int EstimateSize = limite 2;StackWalker. getInstance (Set. of (SHOW_HIDDEN_FRAMES), EstimateSize). camminare (frame - 
    March 8, 2018