The stack-walking API, released as part of Java 9, offers an efficient way to access the execution stack. (The execution stack represents the chain of method calls - it starts with the public static void main(String[])
method or the run method of a thread, contains a frame for each method that was called but did not yet return, and ends at the execution point of the StackWalker
call.) In this article we will explore the different functionalities of the stack-walking API, followed by a look at its performance characteristics.
This article requires working knowledge of Java, particularly lambda expressions and streams.
Who Called Me?
There are situations when you need to know who called your method. For example, to do security checks or to identify the source of a resource leak. Every method call creates a frame on the stack and Java allows code to access the stack, so it can analyze it.
Before Java 9, the way most people would access the stack information was via instantiating a Throwable
and use it to get the stack trace.
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
This works but it is quite costly and hacky. It captures all the frames - except the hidden ones - even if you need only the first 2 and does not give you access to the actual Class
instance in which the method is declared. To get the class you need to extend SecurityManager
that has a protected method getClassContext
that will return an array of Class
.
To address those drawbacks Java 9 introduces the new stack-walking API (with JEP 259). We will now explore the different functionalities of the API followed by a look at its performance characteristics.
StackWalker
Basics
Java 9 ships with a new type, the StackWalker
, which gives access to the stack. We will now see how to get an instance and how to use it to execute a simple stack walk.
Getting a StackWalker
A StackWalker
is easily accessible with the static getInstance
methods:
StackWalker stackWalker1 =
StackWalker.getInstance();
StackWalker stackWalker2 =
StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
StackWalker stackWalker3 =
StackWalker.getInstance(
Set.of(RETAIN_CLASS_REFERENCE, SHOW_HIDDEN_FRAMES));
StackWalker stackWalker4 =
StackWalker.getInstance(Set.of(RETAIN_CLASS_REFERENCE), 32);
The different calls allow you to specify one option or a set of them as well as the estimated size of the number of frames to capture - I will discuss both further below.
Once you have your StackWalker
you can access the stack information using the following methods.
The forEach
Method
The forEach
method will forward all the unfiltered frames to the specified Consumer<StackFrame>
callback. So, for example, to just print the frames you do:
stackWalker.forEach(System.out::println);
Walk the walk
The walk
method takes a function that gets a stream of stack frames and returns the desired result. It has the following signature (plus some wildcards that I removed to make it more readable):
<T> T walk(Function<Stream<StackWalker.StackFrame>, T> function)
You might ask why does it not just return the Stream
? Let's come back to that later. First, we'll see how we can use it. For example, to collect the frames in a List
you would write:
// collect the frames
List<StackWalker.StackFrame> frames = stackWalker.walk(
frames -> frames.collect(Collectors.toList()));
To count them:
// count the number of frames
long nbFrames = stackWalker.walk(
// the lambda returns a long
frames -> frames.count());
One of the big advantages of using the walk
method is that because the stack-walking API lazily evaluates frames, the use of the limit
operator actually reduces the number of frames that are recovered. The following code will retrieve the first two frames, which, as we will see later, is much cheaper than capturing the full stack.
List<StackWalker.StackFrame> caller = stackWalker.walk(
frames -> frames
.limit(2)
.collect(Collectors.toList()));
[caption id="attachment_149082" align="aligncenter" width="1024"] Published by Rory Hyde under CC-BY-SA 2.0 / SitePoint changed colorization and field of view and shares under the same license[/caption]
Advanced StackWalker
Continue reading %Deep Dive into Java 9’s Stack-Walking API%
by Arnaud Roger via SitePoint
No comments:
Post a Comment