-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMemoryManagementIntro.java
More file actions
153 lines (143 loc) · 7.18 KB
/
Copy pathMemoryManagementIntro.java
File metadata and controls
153 lines (143 loc) · 7.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package Phase6_RuntimeMemoryRegexReflection.MemoryAllocation;
/**
* Java Memory Management - Introduction
* -------------------------------------
* "Memory management" is everything the JVM does between you writing
* `new Customer()` and the OS getting the bytes back: where the object
* lives, when it can be reclaimed, and which subsystem of the JVM owns
* the space.
* <p>
*
* Why You Care (even though Java is "garbage-collected")
* ------------------------------------------------------
* - YOU still pick the data structures - they decide allocation rate.
* - YOU configure heap size and the garbage collector.
* - YOU can introduce LEAKS that the GC cannot fix (see MemoryLeaks.java).
* - Understanding the layout helps you tune for latency or throughput.
* <p>
*
* The Big Picture
* ---------------
* <p>
*
* +-----------------------------------------------+
* | JVM Process |
* | |
* | +-----------------------+ |
* | | Method Area | class data, |
* | | (Metaspace since 8) | static fields, |
* | +-----------------------+ constant pool |
* | |
* | +-----------------------+ |
* | | Heap | ALL objects, |
* | | | arrays |
* | +-----------------------+ |
* | |
* | +-----------+ +-----------+ per-thread |
* | | Thread A | | Thread B | stack frames, |
* | | Stack | | Stack | local vars |
* | +-----------+ +-----------+ |
* | |
* | +-----------+ +-----------+ |
* | | PC reg A | | PC reg B | current |
* | +-----------+ +-----------+ bytecode addr |
* | |
* | +-----------+ +-----------+ |
* | | Native | | Native | C/C++ stacks |
* | | Stack A | | Stack B | for JNI calls |
* | +-----------+ +-----------+ |
* +-----------------------------------------------+
* <p>
*
* - Method Area & Heap are SHARED by all threads.
* - Stack, PC, Native stack are PER-THREAD.
* <p>
*
* Lifecycle of a Java Object
* --------------------------
* 1. CREATION - `new` allocates space on the heap (the "young generation").
* 2. USE - method calls move references between stack frames.
* 3. UNREACHABILITY - no live reference points to the object anymore.
* 4. RECLAMATION - the garbage collector eventually reclaims the space
* and may compact / move the surviving objects.
* <p>
*
* Things the Programmer Does NOT Control
* --------------------------------------
* - WHEN the GC runs. `System.gc()` is just a HINT.
* - The exact ADDRESS of an object - it can move between GC cycles.
* - Stack frame layout. The JVM manages it.
* <p>
*
* What This Folder Covers
* -----------------------
* MemoryManagementIntro.java (this file)
* ObjectsInMemory.java - the in-memory layout of an object
* JvmMemoryAreas.java - Method Area / Heap / Stack / PC / Native
* StackVsHeap.java - the most-asked interview question
* GarbageCollection.java - reachability, mark-and-sweep, generations
* GarbageCollectors.java - Serial / Parallel / G1 / ZGC / Shenandoah
* MemoryLeaks.java - patterns that fool the GC and fixes
* ModernMemoryFeatures.java - Java 9..21 (Cleaner, Compact Strings,
* Generational ZGC, virtual-thread memory)
*/
public class MemoryManagementIntro {
public static void main(String[] args) {
section("1) Inspect the JVM running this code");
System.out.println("Java version : " + System.getProperty("java.version"));
System.out.println("Vendor : " + System.getProperty("java.vendor"));
System.out.println("JVM name : " + System.getProperty("java.vm.name"));
System.out.println("JVM version : " + System.getProperty("java.vm.version"));
section("2) Heap sizes from the Runtime API");
Runtime rt = Runtime.getRuntime();
long mb = 1024 * 1024;
System.out.printf("max heap : %5d MB (-Xmx)%n", rt.maxMemory() / mb);
System.out.printf("total heap : %5d MB%n", rt.totalMemory() / mb);
System.out.printf("free heap : %5d MB%n", rt.freeMemory() / mb);
System.out.printf("used heap : %5d MB%n",
(rt.totalMemory() - rt.freeMemory()) / mb);
System.out.println("processors : " + rt.availableProcessors());
section("3) Default garbage collector");
for (java.lang.management.GarbageCollectorMXBean gc :
java.lang.management.ManagementFactory.getGarbageCollectorMXBeans()) {
System.out.println(" GC : " + gc.getName()
+ " (collections so far: " + gc.getCollectionCount() + ")");
}
section("4) Allocate something and watch the used-heap rise");
long usedBefore = rt.totalMemory() - rt.freeMemory();
// Allocate ~ 20 MB of integers
int[] big = new int[5_000_000];
big[0] = 1; // keep reference live
long usedAfter = rt.totalMemory() - rt.freeMemory();
System.out.printf("before allocate : %5d MB%n", usedBefore / mb);
System.out.printf("after allocate : %5d MB (~20 MB int[5_000_000])%n", usedAfter / mb);
section("5) System.gc() is only a HINT");
big = null; // drop the reference
System.gc(); // hint, not a guarantee
long usedAfterGc = rt.totalMemory() - rt.freeMemory();
System.out.printf("after gc : %5d MB (may or may not drop)%n", usedAfterGc / mb);
// OUTPUT (numbers vary by your machine - the SHAPE of the output is the point)
// ====== 1) Inspect the JVM running this code ======
// Java version : 21.0.2
// Vendor : Eclipse Adoptium
// JVM name : OpenJDK 64-Bit Server VM
// JVM version : 21.0.2+13-LTS
// ====== 2) Heap sizes from the Runtime API ======
// max heap : 4096 MB (-Xmx)
// total heap : 256 MB
// free heap : 248 MB
// used heap : 8 MB
// processors : 8
// ====== 3) Default garbage collector ======
// GC : G1 Young Generation (collections so far: 0)
// GC : G1 Old Generation (collections so far: 0)
// ====== 4) Allocate something and watch the used-heap rise ======
// before allocate : 8 MB
// after allocate : 28 MB (~20 MB int[5_000_000])
// ====== 5) System.gc() is only a HINT ======
// after gc : 5 MB (may or may not drop)
}
private static void section(String title) {
System.out.println("\n====== " + title + " ======");
}
}