This article is participating in the Java Theme Month – Java Debug Notes EventActive link

🎓 Do your best and obey the destiny. I am a postgraduate student in Southeast University and a summer intern in Java background development in Ctrip. I love fitness and basketball, and I am willing to share what I have seen and gained related to technology. I follow the public account @flying Veal and get the update of the article as soon as possible

🎁 This article has been included in the “CS-Wiki” Gitee official recommended project, has accumulated 1.7K + STAR, is committed to creating a perfect back-end knowledge system, in the road of technology to avoid detours, welcome friends to come to exchange and study

🍉 If you do not have a good project, you can refer to a project I wrote “Open source community system Echo” Gitee official recommended project, so far has accumulated 700+ STAR, SpringBoot + MyBatis + Redis + Kafka + Elasticsearch + Spring Security +… And provide detailed development documents and supporting tutorials. Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo


Speaking of the underlying workings of threads, you probably know that we’re going to have to cover the JVM today. In fact, we understand the Java runtime data area, also understand the underlying principle of threads, but these things clearly written on paper, there are not many articles on the network, so today I summed up, take you step by step DEBUG, to see how threads run on earth. By the way, the DEBUG method of IDEA is briefly described.

The use of tools should be most of the students are missing, I myself suffered from it, often involuntarily used to row by row with the naked eye bugs (dog head).

Java runtime data area

Tips: This part of the content may be most of the students have a certain understanding, you can skip to the next section.

During the execution of Java programs, the Java virtual machine divides the memory it manages into different data areas, each of which has its own purpose and creation and destruction time.

We’ll use JDK 7’s runtime data area as an example throughout:

Let’s briefly explain what thread sharing and thread private mean.

The so-called thread private, generally speaking, each thread will create a thing belonging to its own, each thread between the private area does not affect each other, independent storage. For example, the program counter is thread private. Each thread has its own program counter without interference.

Thread sharing is simply a public place where anyone can go and store data that can be accessed by all threads.

OK, and then let’s take a look at what each area is used to store. Of course, there will not be too much detailed explanation, otherwise the article will be very bloated, on the basis of understanding the article can let everyone have a basic understanding of each area.

Let’s start with two areas shared by threads:

1) The Java Heap is the largest chunk of memory managed by the Java virtual machine and is created when the virtual machine is started. The sole purpose of this memory area is to hold object instances, and almost all object instances are allocated memory here. This is described in the Java Virtual Machine specification: all object instances and arrays are allocated on the heap.

2) The Method Area, like the Java heap, is an Area of memory shared by each thread. It is used to store data such as class information that has been loaded by the virtual machine, constants, static variables, and code compiled by the just-in-time compiler.

Many people tend to refer to method regions as Permanent Generation, but the two are not equivalent. In layman’s terms, a method area is a specification, and a persistent generation is a way for the HotSpot VIRTUAL machine to implement this specification. For other virtual machines (such as BEA JRockit, IBM J9, etc.) the concept of a persistent generation does not exist.

In addition, for the HotSpot virtual machine, it completely scrapped the concept of persistent generation in JDK 8 and replaced it with a meta-space implemented in local memory like JRockit and J9. Move all of the remaining content of the persistent generation in JDK 7 (mainly type information) into the meta space.

Let’s look at the three thread-private areas:

1) Java Virtual Machine Stacks are made up of Stack frames ** which describe the memory model of Java method execution. That is, each method is executed with a stack frame, which is used to store information such as the local variable table, operand stack, dynamic link, method return address, etc.

The process of each method from invocation to completion of execution corresponds to the process of a stack frame from the virtual machine stack to the stack, of course, the order of the stack is in accordance with the last in first out principle.

The concept of stack frame is very important in the following principle analysis section, you must understand ha.

2) The Native Method Stack is basically the same as the virtual machine Stack. The difference is that the Native Method Stack serves the Native methods used by the VIRTUAL machine, while the virtual machine Stack serves the Java methods (that is, bytecode) executed by the virtual machine.

To explain the concept of Native methods, this concept is found in many languages, not just Java.

“A native method is a Java method whose implementation is provided by non-java code.”

That is, a Native method is an interface, but its implementation is written externally in a non-Java language. Therefore, if the same Native method is invoked by different virtual machines, the result and operation efficiency may be different, because different virtual machines have their own implementation of a Native method, such as the hashCode method of Object class.

This allows Java programs to extend beyond the boundaries of the Java runtime, effectively extending the JVM.

3) The Program Counter Register is a small memory space that can be regarded as a line number indicator of the bytecode executed by the current thread. The bytecode interpreter works by changing the value of this counter to select the next bytecode instruction to be executed. Branch, loop, jump, exception handling, thread recovery and other basic functions need to be completed by this counter.

Because multithreading in the Java virtual machine is implemented by taking turns allocating CPU time slices, each thread needs to have a separate program counter in order for the thread to switch back to the correct execution position.

So what exactly is stored in the program counter?

Understanding the Java Virtual Machine: Advanced Practices and Best Practices for the JVM – Edition 2 provides an answer: If the thread is executing a Java method, the program counter records the address of the virtual machine’s bytecode instructions that are executing. If the Native method is being executed, this counter value is null (Undefined).

Use DEBUG to view the running principle of the thread

Next, let’s look at the running principle of the thread through the DEBUG code:

The logic of the code above is very simple; the main method calls method1, which in turn calls method2.

Look at the figure below, we hit a break point:

OK, run test.main () as DEBUG. Although we do not show the creation thread here, the main call itself is a thread, also called the main thread (main thread), so when we start the program, we will allocate a virtual stack memory to the main thread.

As mentioned above, the virtual machine stack memory is actually a shell, in which data is actually stored in a stack frame, each method corresponds to a stack frame.

So when the main thread calls the main method, it generates a stack frame for the main method, which stores local variables, operand stacks, dynamic links, and the return address of the method.

Now you can see the DEBUG window:

On the left, Frames stands for stack frame. You can see that there is only one main stack frame in the main thread.

Variables on the right is the local variable table stored in the stack frame. You can see that there is now only one local variable in the main stack frame, which is the method parameter args.

Next, DEBUG enters the next step. Let’s take a look at the meaning of each button on the DEBUG interface. There are five buttons in total (you can skip here if you already know) :

1) Step Over: F8

The program runs down one line, and if there is a method call on the current line, the method is executed and returned, and then on to the next line

2) Step Into: F7

The program executes down a line, and if there is a custom method on that line, runs into the custom method (the method that does not go into the official library)

3) Force Step Into: Alt + Shift + F7

The program executes down a line, and if that line has a custom or official library method, runs into that method (that is, any method)

4) Step Out: Shift + F8

If you go into a method during debugging and find it ok, you can use Step Out to execute the method and jump back to the next line where the method was called.

5) Drop frame

After clicking this button, you will go back to the call of the current method and re-execute it, with the values of all context variables going back to that time. As long as there are parent methods in the call chain, you can jump to any of them.


OK, we hit Step Into method1, and you can see that the vm stack has an extra method1 frame in memory:

Click Step Into until you get to method2, and you get another method2 stack frame in the vm stack:

When we Step Into the return N statement in method2, the heap address pointed to by n is returned to M in Method1, and, following the last-in, first-out rule, the method2 stack frame is destroyed from vm stack memory.

Then click Step Over to execute the output statement (Step Into goes to println, Force Step Into goes to Object.toString)

At this point, method1 is done with method1, and the method1 stack frame is destroyed from vm stack memory.

At the end of the next step, the main frame will be destroyed, and there will be no more textures.

Detailed illustration of thread operation principle

Now that I’ve taught you about stack frames, I’m going to take a graphical look at what happens to the data area of the Java runtime when threads are running.

First step, class loading.

Understanding the Java Virtual Machine: Advanced Practices and Best Practices for the JVM – 2nd edition explains class loading as follows: The virtual machine loads the data describing the Class from the Class file (bytecode file) into the memory, verifies, converts, and initializes the data, and finally forms Java types that can be directly used by the VIRTUAL machine. This is the Class loading mechanism of the virtual machine.

The bytecode information loaded in is stored in the method area. Look at the picture below, here for you to understand the convenience, I will not write section code, directly according to the code, you know here is actually byte code on the line:

The main thread calls the main method and generates a main stack frame for that method:

So where does this parameter args come from? That’s right, new from the heap:

The return address of the main method is the program’s exit address.

If the thread is executing a Java method, the program counter will record the address of the virtual machine bytecode instruction being executed, which means that the address of the bytecode instruction corresponding to method1(10) will be put into the program counter. Again, we use the actual code in the image. Good to know:

OK, the CPU enters method1 as instructed by the program counter, and method1 stacks are created:

Once the local variable table and method return address are settled, the specific method call can begin. First, 10 is passed to X, and then y is assigned x + 1, where the program counter is modified to the address of the bytecode instruction corresponding to this code:

M = method2(); At this step, a method2 stack frame is created:

As you can see, the first line of the method2 method creates an Object Object in the heap:

Next, go to the return n in the method2 method; Statement, the heap address pointed to by n is returned to M in Method1, and, following the last-in, first-out rule, method2 stack frames are destroyed from vm stack memory:

Method2 returns the address of the method to which the stack frame points, and we proceedSystem.out.println(m.toString())The method1 stack frame is also destroyed after executing this output statement:

Method1 returns the address to which the stack frame points, and finds that our program has reached the end of its life, and the main stack frame has been destroyed, so it is no longer textured.

Use DEBUG to see how multithreading works

The above is the case of only one thread, in fact, the principle of multi-threading is similar, because the virtual machine stack is private for each thread, nobody interferes with each other, here I will briefly mention a word.

Create Thread breakpoints at the following two locations:

Then run it in DEBUG mode and you’ll see that there are two separate virtual stack Spaces:

Of course, one of the inevitable problems with multithreading is Thread Context Switch, which means that for some reason the CPU stops executing the current Thread and switches to another Thread.

There are several possible reasons for thread context switching:

1) The CPU slice of the thread is used up

2) Garbage collection occurs

3) There are higher priority threads to run

4) The thread itself calls sleep, yield, wait, Join, Park, synchronized, lock and other methods

When A context switch from thread A to thread B occurs, the operating system needs to save the state of the current thread A (so that it can come back later) and restore the state of the other thread B.

This state includes the private program counter for each thread and the information for each stack frame in the virtual machine stack. Obviously, each operating system needs to store so much information that frequent thread context switching will inevitably affect the performance of the program.

| flying veal 🎉 pay close attention to the public, get updates immediately

  • I am a postgraduate student in Southeast University and a summer intern in Java background development of Ctrip. I run a public account “Flying Veal” in my spare time, which was opened on 2020/12/29. Focus on sharing computer fundamentals (data structure + algorithm + computer network + database + operating system + Linux), Java technology stack and other related original technology good articles. The purpose of this public account is to let you can quickly grasp the key knowledge, targeted. Pay attention to the public number for the first time to get the article update, we progress together on the way to growth
  • And recommend personal maintenance of open source tutorial project: CS-Wiki (Gitee recommended project, has accumulated 1.7K + STAR), committed to creating a perfect back-end knowledge system, in the road of technology to avoid detours, welcome friends to come to exchange learning ~ 😊
  • If you don’t have any outstanding projects, you can refer to the Gitee official recommended project of “Open Source Community System Echo” written by me, which has accumulated 700+ star so far. SpringBoot + MyBatis + Redis + Kafka + Elasticsearch + Spring Security +… And provide detailed development documents and supporting tutorials. Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo Echo