With the include directive, the Container has a lot of work to do, but only on the first request. From the second request on, there’s no extra runtime overhead.
The client makes a request for Contact.jsp, which has not been translated. The Container reads the Contact.jsp page to start the translation process.
The container sees the include directive, and combines the source code of Header.jsp and Contact.jsp, and creates/translates that into a Java source file for the generated servlet.
The Container compiles the translated source file into a servlet class. It’s just like any other servlet at this point, and the previous step never has to happen again, unless Contact.jsp changes (or, if your Container is smart and can tell that the included Header.jsp has changed).
To complete the request, the Container loads the newly-compiled class, initializes a servlet (instantiates the servlet then calls init() on the new object), allocates a thread for the request, and calls the _jspService() method. From the second request on, the Container does only step (C): allocates a thread and calls the _jspService() method.