- Путь автоматизатора
- Страницы
- 18 октября 2016
- Stack trace или трассировка стека в Java
- What is a stack trace, and how can I use it to debug my application errors?
- 13 комментариев:
- StackTrace
- Что такое stack trace, и как с его помощью находить ошибки при разработке приложений?
- 1 ответ 1
- Java stack trace on Windows
- 6 Answers 6
- What is a stack trace, and how can I use it to debug my application errors?
- 7 Answers 7
Путь автоматизатора
Блог о тестировании, автоматизации тестирования и Java
Страницы
18 октября 2016
Stack trace или трассировка стека в Java
What is a stack trace, and how can I use it to debug my application errors?
13 комментариев:
в который раз восхищаюсь женским трудолюбием
спасибо. мне приятно что мое трудолюбие оказалось для кого-то полезным 🙂
спасибо за статью!
Спасибо за статью! 🙂
Спасибо за труд!)
You are welcome!
вот стаолкнулся сегодня с этим заданием на javarush — методика конечно поражает «разбирайся сам как хочешь»
чего я только не на придумывал пока не разобрался
в общем в двух словах — просто трекинг методов до ошибки
вот видосик- но тут только описательная часть без кода
https://www.youtube.com/watch?v=9JfCCk9vbgI
вот описание методов на полупереведеннорусском
http://spec-zone.ru/RU/Java/Docs/7/api/java/lang/StackTraceElement.html
короче создаем массив методов до ошибки:
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
методы:
stack.length; — так получаем количество методов в массиве
так можем их перебрать
for (StackTraceElement element: stack)
для инфы: номера методов в стеке
0 — getStackTrace — сам трейсер
1 — имя метода (свое имя)
2 — имя метода кто вызвал [1] — всегда2.
3 — имя метода кто вызвал [2]
4 — и т.д.
stack[2].getMethodName(); — получаем имя вызывающего метода
stack[2].getLineNumber(); — получаем строку в вызвавшем методое
stack[2].getClassName(); — получаем имя класса
Не «отбрасывайте» нижние строки. Из них видно, что IDE запускает из своего класса свой же main, который, используя рефлексию (посмотрите на методы invoke и reflect из sun-библиотеки), в свою очередь, запускает ваш main.
StackTrace
— Привет! Сегодня я расскажу тебе, что такое стек-трейс. Но сначала расскажу, что такое стек.
— Представь себе стопку бумаг — деловых поручений для некоторого исполнителя. Сверху на стопку можно класть новое задание, и с верха стопки задание можно брать. При таком подходе задания будут исполняться не по порядку поступления. Задание, положенное самым последним, будет взято исполнителем самым первым. Такая структура элементов коллекции называется стеком – стопкой.
— В Java для этого есть специальная коллекция – Stack. Это коллекция, у которой есть методы «добавить элемент» и «взять(достать/забрать) элемент». Как ты уже догадался, первым будет взят элемент, добавленный самым последним.
— Хм. Вроде не сложно и понятно.
— Отлично. Тогда сейчас объясню, что такое стек-трейс.
— Представь себе, что в Java функция А вызвала функцию Б , а та вызвала функцию В , а та, в свою очередь, функцию Г . Так вот, чтобы выйти из функции Б , нужно сначала выйти из функции В , а для этого выйти из функции Г . Это очень похоже на стек.
— В стопке тоже, чтобы добраться до какого-то листка с заданием, надо довыполнить все задания, которые положили сверху.
— Ну, некоторая аналогия есть, но не уверен, что я все понял правильно.
— Смотри. Стек – это набор элементов. Как листы в стопке. Чтобы взять третий сверху лист, надо сначала взять второй, а для этого взять первый. Класть и брать листы можно всегда, но всегда взять можно только самый верхний.
— С вызовом функций то же самое. Функция А вызывает функцию Б, а та вызывает функцию В . И чтобы выйти из А , надо сначала выйти из Б , а для этого надо выйти из В .
— Подожди. Если я все правильно понял, то весь этот стек сведется к «взять можно только самый последний положенный лист», «выйти можно только из последней функции, в которую зашли». Так?
— Да. Так вот – последовательность вызовов функций — это и есть «стек вызовов функций», он же просто «стек вызовов». Функция, вызванная последней, должна завершиться самой первой. Давай посмотрим это на примере:
Что такое stack trace, и как с его помощью находить ошибки при разработке приложений?
Иногда при запуске своего приложения я получаю подобную ошибку:
Мне сказали, что это называется «трассировкой стека» или «stack trace». Что такое трассировка? Какую полезную информацию об ошибке в разрабатываемой программе она содержит?
Немного по существу: довольно часто я вижу вопросы, в которых начинающие разработчики, получая ошибку, просто берут трассировки стека и какой-либо случайный фрагмент кода без понимания, что собой представляет трассировка и как с ней работать. Данный вопрос предназначен специально для начинающих разработчиков, которым может понадобиться помощь в понимании ценности трассировки стека вызовов.
1 ответ 1
Простыми словами, трассировка стека – это список методов, которые были вызваны до момента, когда в приложении произошло исключение.
Простой случай
В указанном примере мы можем точно определить, когда именно произошло исключение. Рассмотрим трассировку стека:
Это пример очень простой трассировки. Если пойти по списку строк вида «at…» с самого начала, мы можем понять, где произошла ошибка. Мы смотрим на верхний вызов функции. В нашем случае, это:
Для отладки этого фрагмента открываем Book.java и смотрим, что находится на строке 16 :
Это означает то, что в приведенном фрагменте кода какая-то переменная (вероятно, title ) имеет значение null .
Пример цепочки исключений
Иногда приложения перехватывают исключение и выбрасывают его в виде другого исключения. Обычно это выглядит так:
Трассировка в этом случае может иметь следующий вид:
В этом случае разница состоит в атрибуте «Caused by» («Чем вызвано»). Иногда исключения могут иметь несколько секций «Caused by». Обычно необходимо найти исходную причину, которой оказывается в самой последней (нижней) секции «Caused by» трассировки. В нашем случае, это:
Аналогично, при подобном исключении необходимо обратиться к строке 22 книги Book.java , чтобы узнать, что вызвало данное исключение – NullPointerException .
Еще один пугающий пример с библиотечным кодом
Как правило, трассировка имеет гораздо более сложный вид, чем в рассмотренных выше случаях. Приведу пример (длинная трассировка, демонстрирующая несколько уровней цепочек исключений):
В этом примере приведен далеко не полный стек вызовов. Что вызывает здесь наибольший интерес, так это поиск функций из нашего кода – из пакета com.example.myproject . В предыдущем примере мы сначала хотели отыскать «первопричину», а именно:
Однако все вызовы методов в данном случае относятся к библиотечному коду. Поэтому мы перейдем к предыдущей секции «Caused by» и найдем первый вызов метода из нашего кода, а именно:
Java stack trace on Windows
I need to get a stack trace for a JVM process running on a client machine that uses windows.
The client has the JRE installed but not the JDK.
I want to use JStack but it is not installed and we can’t install a JDK on the client’s machine. I also tried using AdaptJ stack trace product from a Java Webstart Session but that didn’t work because we remote in and get an error about not being the session that started the application at a specified PID.
Essentially I want a way to install JStack without installing the JDK.
6 Answers 6
You probably want to use SendSignal, which was designed for exactly this purpose.
The JDK and associated tools work fine whether «installed» or not, if you just zip up and extract it to a temporary directory, you should be able to run jstack. (No PATH or JAVA_HOME modifications necessary). Just make sure you use the same version that corresponds to the JRE your client has the application running with. At least in the case of JConsole, it seems to fuss if the versions are different. I’m not sure if jstack behaves the same way.
I’m not saying this is the ideal solution, just that it would work. I think jdigital and Eddie’s suggestions are better first bets, and even though this shouldn’t interfere with an existing java installation the same way running the installer would, the customer may disagree regardless.
jstack and jps are part of tools.jar of the JDK. Also attach.dll is required to attach jstack to a process.
Ofcourse the tools.jar and attach.dll are not part of JRE.
To make jstack work on a systems which has no JDK (mostly Windows), I usually do the following.
What is a stack trace, and how can I use it to debug my application errors?
Sometimes when I run my application it gives me an error that looks like:
People have referred to this as a «stack trace». What is a stack trace? What can it tell me about the error that’s happening in my program?
About this question — quite often I see a question come through where a novice programmer is «getting an error», and they simply paste their stack trace and some random block of code without understanding what the stack trace is or how they can use it. This question is intended as a reference for novice programmers who might need help understanding the value of a stack trace.
7 Answers 7
In simple terms, a stack trace is a list of the method calls that the application was in the middle of when an Exception was thrown.
Simple Example
With the example given in the question, we can determine exactly where the exception was thrown in the application. Let’s have a look at the stack trace:
This is a very simple stack trace. If we start at the beginning of the list of «at . «, we can tell where our error happened. What we’re looking for is the topmost method call that is part of our application. In this case, it’s:
To debug this, we can open up Book.java and look at line 16 , which is:
This would indicate that something (probably title ) is null in the above code.
Example with a chain of exceptions
Sometimes applications will catch an Exception and re-throw it as the cause of another Exception. This typically looks like:
This might give you a stack trace that looks like:
What’s different about this one is the «Caused by». Sometimes exceptions will have multiple «Caused by» sections. For these, you typically want to find the «root cause», which will be one of the lowest «Caused by» sections in the stack trace. In our case, it’s:
Again, with this exception we’d want to look at line 22 of Book.java to see what might cause the NullPointerException here.
More daunting example with library code
Usually stack traces are much more complex than the two examples above. Here’s an example (it’s a long one, but demonstrates several levels of chained exceptions):
In this example, there’s a lot more. What we’re mostly concerned about is looking for methods that are from our code, which would be anything in the com.example.myproject package. From the second example (above), we’d first want to look down for the root cause, which is:
However, all the method calls under that are library code. So we’ll move up to the «Caused by» above it, and look for the first method call originating from our code, which is:
Like in previous examples, we should look at MyEntityService.java on line 59 , because that’s where this error originated (this one’s a bit obvious what went wrong, since the SQLException states the error, but the debugging procedure is what we’re after).
What is a Stacktrace?
A stacktrace is a very helpful debugging tool. It shows the call stack (meaning, the stack of functions that were called up to that point) at the time an uncaught exception was thrown (or the time the stacktrace was generated manually). This is very useful because it doesn’t only show you where the error happened, but also how the program ended up in that place of the code. This leads over to the next question:
What is an Exception?
An Exception is what the runtime environment uses to tell you that an error occurred. Popular examples are NullPointerException, IndexOutOfBoundsException or ArithmeticException. Each of these are caused when you try to do something that is not possible. For example, a NullPointerException will be thrown when you try to dereference a Null-object:
How should I deal with Stacktraces/Exceptions?
At first, find out what is causing the Exception. Try googling the name of the exception to find out what the cause of that exception is. Most of the time it will be caused by incorrect code. In the given examples above, all of the exceptions are caused by incorrect code. So for the NullPointerException example you could make sure that a is never null at that time. You could, for example, initialise a or include a check like this one:
This way, the offending line is not executed if a==null . Same goes for the other examples.
Sometimes you can’t make sure that you don’t get an exception. For example, if you are using a network connection in your program, you cannot stop the computer from loosing it’s internet connection (e.g. you can’t stop the user from disconnecting the computer’s network connection). In this case the network library will probably throw an exception. Now you should catch the exception and handle it. This means, in the example with the network connection, you should try to reopen the connection or notify the user or something like that. Also, whenever you use catch, always catch only the exception you want to catch, do not use broad catch statements like catch (Exception e) that would catch all exceptions. This is very important, because otherwise you might accidentally catch the wrong exception and react in the wrong way.
Why should I not use catch (Exception e) ?
Let’s use a small example to show why you should not just catch all exceptions:
What this code is trying to do is to catch the ArithmeticException caused by a possible division by 0. But it also catches a possible NullPointerException that is thrown if a or b are null . This means, you might get a NullPointerException but you’ll treat it as an ArithmeticException and probably do the wrong thing. In the best case you still miss that there was a NullPointerException. Stuff like that makes debugging much harder, so don’t do that.
TLDR
- Figure out what is the cause of the exception and fix it, so that it doesn’t throw the exception at all.
- If 1. is not possible, catch the specific exception and handle it.
- Never just add a try/catch and then just ignore the exception! Don’t do that!
- Never use catch (Exception e) , always catch specific Exceptions. That will save you a lot of headaches.