update
All checks were successful
Deploy / deploy (push) Successful in 11s

This commit is contained in:
2026-04-22 09:02:23 +03:00
parent 77165a7999
commit 40407fcabc
35 changed files with 636 additions and 44 deletions

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB

View File

@@ -31,14 +31,14 @@ The behaviour of the Java compiler is described by the [Java Language Specificat
Let's talk about compilers a little bit. For example if we will take *C++*. If we take C++ compiler for *x86-64* platform and *Windows* operating system, and launch the compiler on source code it will turn it directly into assembly code.
![C++ code compilation under x86-64](assets/cpp-x86-64-compilation.svg)
*Img. X -- C++ code compilation process under x86-64 architecture.*
*Img. 3 -- C++ code compilation process under x86-64 architecture.*
But what if I want to run my program on *Linux* instead of Windows. I will need to take a different compiler under different operating system and recompile my code using a new compiler. It's not very convenient.
Java tries to protect us from that. By converting the *Java source code* into *Java byte code*. And then the *byte code* will be ran on the *Java virtual machine* which will run our program on the native processor.
![Java code compilation](assets/java-code-compilation.svg)
*Img. X -- Java code compilation*
*Img. 4 -- Java code compilation*
This approach allows to change only **JVM** according to our platform (*x86_64, ARM, ...*) and operating system (*Windows, MacOS, GNU-Linux, ...*) while *byte code* stays the same. We can only write our code once, than compile it and run under everywhere.
@@ -95,7 +95,7 @@ Some of the most popular JVMs right now are:
- Azul Systems
- Excelsior JET
The disadvantage of such system is in the connection between JVM and a native processing unit. In case of C++ compiler that we reviewed earlier the source code is compiled directly into machine-code but in case with Java it is compiled into byte-code. And so the problem is to develop such a JVM that would quickly turn our byte-code into machine-code. Anyway it takes extra time. That's why it mostly will be slower than direct compilation into machine-code. So ultimately while we have the advantage of compiling out code only once, we have the disadvantage of turning byte-code into machine-code slower.
The disadvantage of such system is in the connection between JVM and a native processing unit. In case of C++ compiler that we reviewed earlier the source code is compiled directly into machine-code but in case with Java it is compiled into byte-code. And so the problem is to develop such a JVM that would quickly turn our byte-code into machine-code. Anyway it takes extra time. That's why it mostly will be slower than direct compilation into machine-code. So ultimately while we have the advantage of compiling our code only once, we have the disadvantage of turning byte-code into machine-code slower.
None the less, there is a way to speed up this process which is called JIT - Just In Time compilation. How does it work? While our program is running some of the instructions or functions turns directly into processor commands.
@@ -104,12 +104,12 @@ None the less, there is a way to speed up this process which is called JIT - Jus
For example we have `int` which is represented with 4 bytes of data which is directly stored in memory.
![`int` in memory](assets/int-in-memory.svg)
*Img. X -- `int` in memory*
*Img. 5 -- `int` in memory*
But what if we have a `String`. How many memory cells does this string take? We don't know. We will say that our `String` that has length of 5 symbols is stored at `0x12347865`. We defined an address where this string is located in memory. And somewhere in the memory of our programm will be a large buffer where the 5 cells will be stored.
![`String` in memory](assets/string-in-memory.svg)
*Img. X -- `String` in memory*
*Img. 6 -- `String` in memory*
But what do we do with that buffer? We won't need it forever and so sometimes we need to clear that buffer. In case with C/C++ whoever created the memory for that string is in charge of clearing it. There are also languages with garbage collection such as Java and Python. The purpose of the **Garbage Collector** is to automatically find variables that we no longer need and clear their memory.
@@ -124,10 +124,10 @@ if (someCondition) {
} // no links
```
After the `if`-statement we no longer need `x` or `y`. Every variable in this case `x` and `y` is the link to our array (`[1, 3, 7]`). After we left the `if`-statement the amount of links to the array is zero, so we can safely delete the array. This approach is implemented in Python. The problem is that if we have to objects linked to one another and there are no external links, they will not be deleted by garbage collector since there link counter is 1.
After the `if`-statement we no longer need `x` or `y`. Every variable in this case `x` and `y` is the link to our array (`[1, 3, 7]`). After we left the `if`-statement the amount of links to the array is zero, so we can safely delete the array. This approach is implemented in Python. The problem is that if we have two objects linked to one another and there are no external links, they will not be deleted by garbage collector since there link counter is 1.
![Edge case for link couting](assets/edge-case-for-link-counting.svg)
*Img. X -- Edge case for link counting*
*Img. 7 -- Edge case for link counting*
The advanced way of implementing the garbage collection is *traversing the graph of links* which is implemented in Java, C# and Go.