Checking lesson access...
How a Computer Executes a Program
See the roles of the CPU, memory and storage, and follow Java code from `.java` source through the compiler and bytecode to the JVM.
You are viewing a free preview lesson.
Lesson Overview
In the previous lesson, Nur's mark calculator was Java source code: text a person can read. The computer's processor cannot execute that text directly. Java source code is first compiled into bytecode, and then the Java Virtual Machine (JVM) executes that bytecode, working with the operating system and the hardware underneath.
Knowing this path explains a lot of what you will see as a beginner: why there are .java and .class files, why some errors appear before the program runs and others only while it runs, why the same Java program runs on Windows, macOS and Linux, and what happens when you press Run in an IDE. In this lesson, we follow a program from storage to the CPU.
Learning Objectives
After completing this lesson, you will be able to:
- Explain the roles of CPU, memory, and storage
- Understand the difference between machine language and high-level languages
- Explain what a compiler does
- Explain the flow from Java source code to a running program
- Understand the difference between
.javaand.classfiles - Explain why bytecode and the JVM are needed
What Happens in a Computer When a Program Runs?
When a program runs, several parts of hardware and software work together. The most important ones for us are the CPU, memory, storage, and the operating system. A simplified view of program execution:
Drawing diagram…
CPU
The CPU — Central Processing Unit executes computer instructions: calculations, comparisons, moving data, reading from and writing to memory, and choosing the next instruction based on a condition. Suppose we have:
int firstNumber = 10;
int secondNumber = 20;
int total = firstNumber + secondNumber;
The programmer only wrote firstNumber + secondNumber, but at a lower level, the computer may need to perform multiple operations such as loading values, adding them, and storing the result. One major advantage of using a high-level programming language is that the programmer does not need to write these low-level instructions directly.
Memory and Storage
While a program is running, RAM is generally used to store temporary data. For example, while this program is running, the data required for these values is stored in memory:
int age = 30;
String name = "Sakib";
RAM is volatile: its data does not remain when the computer is powered off. In contrast, storage keeps long-term data, for example on an SSD, an HDD, or an external drive. Storage holds the operating system, applications, Java source files and compiled files, databases, images and documents.
Difference Between Memory and Storage
| Topic | Memory | Storage |
|---|---|---|
| Common example | RAM | SSD / HDD |
| Purpose | Temporary data for running programs | Long-term data |
| Speed | Generally faster | Comparatively slower |
| When power is off | Data is lost | Data remains |
| Example | Variable, object | File, application |
Simply put:
Programs are stored in storage and run in memory.
Operating System
The operating system manages the computer's hardware resources and running programs; Windows, macOS, and Linux are examples. It shares out CPU time, allocates memory, manages the file system and running processes, and controls network and device resources. When a Java application runs, the operating system runs a Java process and provides it with the CPU and memory resources it needs.
What Kind of Instructions Does a Computer Understand?
At the lowest level, information in a computer is represented in binary form, which uses only 0 and 1. Low-level instructions that a processor can execute directly are called machine instructions or machine language. Machine instructions can depend on the processor architecture, such as x86-64 or ARM.
Writing large programs directly in machine language is extremely difficult for humans. This is why we use high-level programming languages.
High-Level Programming Language
Java is a high-level programming language:
int total = firstPrice + secondPrice;
By reading this code, we can easily understand that two prices are being added and the result is stored in total. High-level languages such as Java, Python, Go, and JavaScript give us readable code that is easier to maintain, faster development, reusable building blocks, and separation from low-level hardware details.
The CPU Does Not Directly Execute Source Code
Java source code such as int total = 10 + 20; is human-readable, but the CPU does not directly understand Java syntax. Java source code must be translated into an intermediate format that the Java runtime can execute. The first step in this process is compilation.
Compiler
A compiler is a program that analyzes source code and translates it into another format. The Java compiler can detect different kinds of problems while checking source code. Here, a text value is being assigned to an int variable, so the Java compiler will not allow this code to compile:
int age = "twenty";
The compiler can detect many syntax and type-related errors before the program runs.
Compilation
The process of converting source code into a translated format using a compiler is called compilation. In Java, the translated code is bytecode:
Drawing diagram…
Compiled and Interpreted Execution
Classifying programming languages only as compiled or interpreted is not always completely accurate. In simplified terms:
- Compilation: source code is translated into another format before the program executes.
- Interpretation: instructions are read and executed at runtime.
Modern runtimes may use compilation, interpretation, and runtime optimization together, and Java also uses such a hybrid execution model.
How Does a Java Program Execute?
A simplified Java program execution flow:
Drawing diagram…
Step 1: Java Source Code
Java source code is generally written in a .java file, for example Main.java:
public class Main {
public static void main(String[] args) {
System.out.println("Hello Java");
}
}
This is human-readable source code written by the developer.
Step 2: Compile the Source Code
The Java compiler command is:
javac Main.java
If compilation is successful, it creates Main.class, a file that contains Java bytecode.
Step 3: Bytecode
Bytecode is an intermediate instruction format created by the Java compiler. It is not Java source code, and it is not machine code for a particular CPU: it is an instruction format made for the JVM.
Step 4: JVM Runs the Program
The JVM — Java Virtual Machine is the runtime environment that executes Java bytecode. To run the program:
java Main
The JVM loads the Main class, and execution of a standalone Java application begins from the main method.
Output:
Hello Java
Notice that the .class extension is not included in the java Main command.
Role of the JVM
The main responsibility of the JVM is to execute bytecode. In addition, it provides runtime services: loading classes, managing memory (including garbage collection, which frees memory a program no longer uses), managing threads, and optimizing code while it runs. You do not need to understand the JVM's internal architecture in detail yet; we will discuss the necessary parts later as we continue learning Java.
JIT Compiler
Modern JVMs can use a JIT — Just-In-Time Compiler to improve runtime performance. In simplified form:
Drawing diagram…
The JVM can use runtime information to optimize frequently executed code. This is why Java execution is not only traditional interpretation; compilation and runtime optimization can work together.
Java Platform Independence
The Java compiler generally produces bytecode instead of a platform-specific machine executable. The same bytecode can run on different platforms when a compatible JVM is available.
Drawing diagram…
The important points are:
- Bytecode can be portable
- The JVM is platform-specific
A JVM for Windows works with Windows, while a JVM for Linux works with Linux. This model forms the basis of Java's portability, an idea often expressed as:
Write once, run anywhere.
However, if an application uses operating-system-specific paths, native libraries, or platform-specific dependencies, additional compatibility considerations may be required.
.java and .class
Keep the two file types apart: a .java file, such as Main.java, holds the source code the developer writes, and a .class file, such as Main.class, holds the bytecode the Java compiler generates from it.
Compilation and Execution
These are two separate stages, with the two commands from Steps 2 and 4. During compilation (javac Main.java), the source code is checked and bytecode is generated. During execution (java Main), the JVM runs that bytecode. Simply put:
Compilation prepares the code, while execution runs the code.
Compilation Error vs. Runtime Error
Lesson 1.01 called these syntax errors and runtime errors; now we can say where each one is caught.
Compilation Error
A compilation error is found by javac, before the program runs. System.out.println("Hello") without its semicolon, or int age = "twenty"; from the Compiler section, never becomes a .class file, so there is nothing for the JVM to run until it is fixed.
Runtime Error
A runtime error gets past the compiler and appears while the JVM executes the bytecode. int result = 10 / 0; compiles, but the program fails when it reaches that line. That means:
Successful compilation does not mean that a program will be error-free at runtime.
What Happens When You Press Run in an IDE?
An IDE such as IntelliJ IDEA performs many tasks automatically. In simplified form:
Drawing diagram…
An IDE makes development easier, but the Java compiler compiles Java code and the JVM executes the bytecode.
Relationship Between Hardware, OS, and JVM
A Java application can be thought of in layers:
Java Application
↓
JVM
↓
Operating System
↓
Hardware
- Java Application: the developer's program logic
- JVM: executes Java bytecode and provides runtime services
- Operating System: manages processes, memory, files, and hardware resources
- Hardware: CPU, RAM, storage, and physical devices
Because of this abstraction, a Java developer generally does not need to work with processor-specific instructions when writing normal application code.
Why Do We Need to Know These Concepts?
You will meet this path every day: when an error message comes from the compiler rather than from a running program, when you look for a .class file, or when the same program behaves alike on a classmate's laptop with a different operating system. Knowing which stage you are in tells you where to look for the cause.
Practice Exercise 1: Execution Order
Solutions: lesson 1.22.
Arrange the following steps in the correct order:
- JVM executes the bytecode
- Java source code is written
- The program produces output
- Java compiler generates bytecode
Practice Exercise 2: Compilation or Runtime?
Determine whether each situation is a problem during the compilation stage or runtime stage.
Situation 1
A semicolon is missing at the end of a statement.
Situation 2
The program divides an integer value by zero.
Situation 3
A text value is assigned to an int variable.
Situation 4
The file that the program is trying to open cannot be found.
Practice Exercise 3: Java Execution Flow
Write the Java execution flow using the following terms:
- Source code
- Java compiler
- Bytecode
- JVM
- CPU
- Output
Knowledge Check
Question 1
What is the main difference between memory and storage?
Question 2
Why do we use high-level programming languages?
Question 3
What does a compiler do?
Question 4
What are the extensions of a Java source file and a compiled file?
Question 5
What is bytecode?
Question 6
What is the role of the JVM?
Question 7
What is the difference between compilation and execution?
Question 8
How does Java's platform independence work?
Knowledge Check Answers
Answer 1
Memory stores temporary data for running programs. Storage preserves long-term files and data.
Answer 2
A high-level language makes code readable and maintainable for humans and removes the need for programmers to write low-level processor instructions directly.
Answer 3
A compiler analyzes source code and translates it into another format. The Java compiler produces bytecode from Java source code.
Answer 4
A Java source file has the .java extension, and a compiled bytecode file has the .class extension.
Answer 5
Bytecode is an intermediate instruction format produced by the Java compiler that the JVM can execute.
Answer 6
The JVM executes Java bytecode and provides services such as memory management, class loading, and runtime optimization.
Answer 7
Compilation creates bytecode from source code. During execution, the JVM runs that bytecode.
Answer 8
The Java compiler produces bytecode instead of a platform-specific executable. When a compatible platform-specific JVM is available, the same bytecode can run on different operating systems.
Lesson Summary
- The CPU executes instructions, memory holds temporary data for running programs, storage keeps long-term data, and the operating system manages these resources.
- Programs are stored in storage and run in memory.
- A processor executes machine instructions directly. High-level languages such as Java let you write readable code instead.
- The Java compiler (
javac) translates a.javasource file into a.classfile containing bytecode. - The JVM executes that bytecode and provides runtime services. A JIT compiler can turn frequently executed code into native machine code.
- Bytecode can be portable, while the JVM is platform-specific. This is the basis of "Write once, run anywhere."
- Compilation and execution are separate stages. Successful compilation does not mean a program will be error-free at runtime.
Think first
Coming soonCheckpoint questions that ask you to commit to an answer before the lesson shows it.