JVM 内存区域划分与垃圾回收机制详解

引言

Java虚拟机(JVM)是Java程序运行的核心环境,其内存管理和垃圾回收机制直接影响着应用程序的性能和稳定性。深入理解JVM内存区域划分和垃圾回收机制,对于编写高性能Java程序、进行内存调优、解决内存泄漏问题具有重要意义。

JVM内存区域划分

程序计数器(Program Counter Register)

程序计数器是JVM内存中最小的内存区域,用于记录当前线程执行的字节码指令地址。

// 程序计数器相关概念演示

public class ProgramCounterExample {

// 模拟字节码执行过程

public static void executeBytecode() {

int a = 1; // 程序计数器指向这行指令

int b = 2; // 程序计数器递增,指向下一行

int c = a + b; // 程序计数器继续递增

System.out.println(c);

}

// 线程切换时程序计数器的保存与恢复

public static void threadSwitching() {

Thread thread1 = new Thread(() -> {

// 每个线程都有独立的程序计数器

for (int i = 0; i < 100; i++) {

System.out.println("Thread 1: " + i);

try {

Thread.sleep(10);

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}

});

Thread thread2 = new Thread(() -> {

// 每个线程的程序计数器独立记录执行位置

for (int i = 0; i < 100; i++) {

System.out.println("Thread 2: " + i);

try {

Thread.sleep(10);

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}

});

thread1.start();

thread2.start();

}

// 程序计数器的唯一无内存溢出区域

public static void noOutOfMemory() {

// 程序计数器不会发生OutOfMemoryError

// 因为它只存储当前线程执行的字节码地址

// 每个线程的程序计数器大小固定

}

}

虚拟机栈(Java Virtual Machine Stacks)

虚拟机栈描述的是Java方法执行的内存模型,每个方法执行时都会创建一个栈帧。

// 虚拟机栈深度测试

public class VirtualMachineStackExample {

private static int stackDepth = 0;

// 递归调用测试栈深度

public static void recursiveCall() {

stackDepth++;

try {

recursiveCall();

} catch (StackOverflowError e) {

System.out.println("Maximum stack depth: " + stackDepth);

System.out.println("Stack overflow occurred: " + e.getMessage());

throw e;

}

}

// 栈帧结构演示

public static int calculateSum(int n) {

if (n <= 1) {

return 1; // 栈帧1:返回1

}

int result = n + calculateSum(n - 1); // 栈帧2,3,4...

return result; // 每个栈帧返回计算结果

}

// 局部变量表演示

public static void localVarTable() {

int localVar1 = 10; // 局部变量表slot 0

String localVar2 = "test"; // 局部变量表slot 1

double localVar3 = 3.14; // 局部变量表slot 2,3 (double占2个slot)

// 每个方法都有独立的局部变量表

// 存储方法参数、局部变量等

}

// 操作数栈演示

public static int operationStackDemo() {

int a = 10; // 加载到操作数栈

int b = 20; // 加载到操作数栈

int c = a + b; // 从操作数栈弹出a,b,计算结果压入栈

return c; // 返回值压入操作数栈

}

// 动态链接演示

public static void dynamicLinking() {

// 每个栈帧都包含一个指向运行时常量池的引用

// 用于支持方法调用过程中的动态链接

String str = "Hello"; // 常量池引用

System.out.println(str); // 动态链接到String类的toString方法

}

// 方法返回地址

public static int methodReturnAddress() {

int result = calculateSum(5); // 调用方法

// 方法执行完毕后,返回到调用处的下一条指令

return result;

}

}

本地方法栈(Native Method Stacks)

本地方法栈为虚拟机使用到的Native方法服务。

// 本地方法栈相关概念

public class NativeMethodStackExample {

// 声明本地方法

public native void nativeMethod();

// 本地方法调用示例

public void callNativeMethod() {

// 调用本地方法时,JVM会在本地方法栈中创建栈帧

nativeMethod();

}

// 本地方法栈溢出示例(理论演示)

public static void nativeStackOverflow() {

// 在实际使用中,本地方法栈也可能出现栈溢出

// 但这种情况相对较少见

}

static {

// 加载本地库

System.loadLibrary("nativeLibrary");

}

}

Java堆(Java Heap)

Java堆是JVM管理的内存中最大的一块,所有线程共享,用于存放对象实例。

// Java堆内存管理演示

public class JavaHeapExample {

// 对象分配演示

public static void objectAllocation() {

// 对象在堆中分配

String str = new String("Hello World"); // 字符串对象在堆中

User user = new User("Alice", 25); // User对象在堆中

int[] array = new int[1000]; // 数组对象在堆中

}

// 堆内存溢出示例

public static void heapOutOfMemory() {

List list = new ArrayList<>();

int count = 0;

try {

while (true) {

// 持续分配大对象,直到堆内存不足

list.add(new byte[1024 * 1024]); // 每次分配1MB

count++;

if (count % 100 == 0) {

System.out.println("Allocated " + count + " MB");

}

}

} catch (OutOfMemoryError e) {

System.out.println("Heap OutOfMemoryError occurred: " + e.getMessage());

System.out.println("Allocated approximately: " + count + " MB");

}

}

// 堆内存区域划分

public static class HeapRegionDemo {

// 新生代(Young Generation)

// - Eden区:新对象分配区域

// - Survivor区:Survivor From和Survivor To

// 老年代(Old Generation)

// - 存放经过多次GC后仍然存活的对象

// 永久代/元空间(Permanent Generation/Metaspace)

// - 存放类信息、常量、静态变量等

public static void generationalDemo() {

// 大多数对象在Eden区分配

Object obj1 = new Object(); // 分配在Eden区

// 经过一次Minor GC后,存活对象进入Survivor区

// 经过多次GC后,进入老年代

}

}

// 大对象直接进入老年代

public static void largeObjectAllocation() {

// 大对象(如大数组)可能直接分配到老年代

// 以避免在新生代之间频繁复制

byte[] largeArray = new byte[2 * 1024 * 1024]; // 2MB大数组

}

// 对象年龄计数器

public static void objectAgeCounter() {

// 每次Minor GC后,对象年龄+1

// 当年龄达到阈值(默认15)时,进入老年代

Object obj = new Object();

// 经过15次GC后,obj可能进入老年代

}

}

// 示例用户类

class User {

private String name;

private int age;

public User(String name, int age) {

this.name = name;

this.age = age;

}

public String getName() {

return name; }

public int getAge() {

return age; }

}

方法区(Method Area)

方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

// 方法区相关概念演示

public class MethodAreaExample {

// 静态变量存储在方法区

private static String staticVar = "Static Variable";

private static final String CONSTANT = "Constant Value";

// 类信息存储在方法区

public static class InnerClass {

private String innerField;

public InnerClass(String innerField) {

this.innerField = innerField;

}

}

// 方法区溢出示例

public static void methodAreaOutOfMemory() {

// 在JDK 8之前,方法区是永久代,容易出现内存溢出

// 在JDK 8及以后,方法区被元空间替代

// 动态生成大量类来测试方法区溢出(需要特殊工具)

// 例如使用CGLIB动态生成类

}

// 运行时常量池演示

public static void runtimeConstantPool() {

String str1 = "Hello";

String str2 = "Hello";

// str1和str2指向常量池中的同一个对象

String str3 = new String("Hello");

// str3指向堆中的新对象

System.out.println(str1 == str2); // true

System.out.println(str1 == str3); // false

}

// 字符串常量池

public static void stringConstantPool() {

// 字符串常量池是方法区的一部分

String s1 = "test";

String s2 = "test";

String s3 = new String("test");

String s4 = s3.intern();

System.out.println(s1 == s2); // true

System.out.println(s1 == s3); // false

System.out.println(s1 == s4); // true

}

}

垃圾回收算法

标记-清除算法(Mark-Sweep)

标记-清除算法是最基础的垃圾收集算法,分为标记和清除两个阶段。

// 标记-清除算法实现

public class MarkSweepGC {

// 模拟对象标记过程

static class MockObject {

private boolean marked = false;

private MockObject next;

public MockObject(MockObject next) {

this.next = next;

}

public boolean isMarked() {

return marked; }

public void mark() {

this.marked = true; }

public void unmark() {

this.marked = false; }

public MockObject getNext() {

return next; }

}

private MockObject root; // GC Root

// 标记阶段

public void markPhase() {

if (root != null) {

markObject(root);

}

}

private void markObject(MockObject obj) {

if (obj != null && !obj.isMarked()) {

obj.mark();

// 递归标记引用的对象

markObject(obj.getNext());

}

}

// 清除阶段

public void sweepPhase() {

// 遍历堆中的所有对象,清除未标记的对象

// 实际JVM中会有更复杂的实现

System.out.println("Sweeping unmarked objects...");

}

// 算法特点分析

public void algorithmCharacteristics() {

System.out.println("标记-清除算法特点:");

System.out.println("1. 简单易实现");

System.out.println("2. 效率不高(需要遍历所有对象)");

System.out.println("3. 会产生内存碎片");

System.out.println("4. 标记和清除过程都需要暂停程序");

}

}

复制算法(Copying)

复制算法将内存按容量划分为大小相等的两块,每次只使用其中一块。

// 复制算法实现

public class CopyingGC {

static class MockObject {

private int id;

private MockObject next;

private boolean copied = false;

public MockObject(int id, MockObject next) {

this.id = id;

this.next = next;

}

public int getId() {

return id; }

public MockObject getNext() {

return next; }

public boolean isCopied() {

return copied; }

public void setCopied(boolean copied) {

this.copied = copied; }

}

// 模拟Eden区和Survivor区

private MockObject[] fromSpace = new MockObject[1000];

private MockObject[] toSpace = new MockObject[1000];

private int fromIndex = 0;

private int toIndex = 0;

// 复制过程

public void copyLiveObjects() {

// 从fromSpace复制存活对象到toSpace

for (int i = 0; i < fromIndex; i++) {

MockObject obj = fromSpace[i];

if (obj != null && isLiveObject(obj)) {

// 假设isLiveObject判断对象是否存活

toSpace[toIndex++] = obj;

obj.setCopied(true);

}

}

// 交换fromSpace和toSpace

MockObject[] temp = fromSpace;

fromSpace = toSpace;

toSpace = temp;

fromIndex = toIndex;

toIndex = 0;

System.out.println("Copying completed, fromIndex: " + fromIndex);

}

// 判断对象是否存活(简化实现)

private boolean isLiveObject(MockObject obj) {

// 在实际GC中,会通过GC Root可达性分析判断

return obj.getId() % 2 == 0; // 假设偶数ID的对象存活

}

// 算法特点分析

public void algorithmCharacteristics() {

System.out.println("复制算法特点:");

System.out.println("1. 实现简单,运行高效");

System.out.println("2. 不会产生内存碎片");

System.out.println("3. 需要浪费一半内存空间");

System.out.println("4. 适合新生代(存活对象少)");

}

// 对象分配

public void allocateObject(int id) {

if (fromIndex < fromSpace.length) {

fromSpace[fromIndex++] = new MockObject(id, null);

} else {

System.out.println("Eden space full, triggering GC");

copyLiveObjects();

}

}

}

标记-整理算法(Mark-Compact)

标记-整理算法结合了标记-清除和复制算法的优点。

// 标记-整理算法实现

public class MarkCompactGC {

static class MockObject {

private int id;

private MockObject next;

private boolean marked = false;

private int newAddress = -1;

public MockObject(int id, MockObject next) {

this.id = id;

this.next = next;

}

public int getId() {

return id; }

public MockObject getNext() {

return next; }

public boolean isMarked() {

return marked; }

public void mark() {

this.marked = true; }

public int getNewAddress() {

return newAddress; }

public void setNewAddress(int address) {

this.newAddress = address; }

}

private MockObject[] heap = new MockObject[1000];

private int heapSize = 0;

// 标记阶段

public void markPhase() {

// 从GC Roots开始标记可达对象

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null) {

markReachable(heap[i]);

}

}

}

private void markReachable(MockObject obj) {

if (obj != null && !obj.isMarked()) {

obj.mark();

// 标记引用的对象

markReachable(obj.getNext());

}

}

// 整理阶段

public void compactPhase() {

int toIndex = 0;

// 将存活对象移动到内存的一端

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null && heap[i].isMarked()) {

if (toIndex != i) {

heap[toIndex] = heap[i];

heap[i] = null; // 清除原位置

}

heap[toIndex].setNewAddress(toIndex);

toIndex++;

} else if (heap[i] != null) {

heap[i] = null; // 清除死亡对象

}

}

heapSize = toIndex;

System.out.println("Compaction completed, heapSize: " + heapSize);

}

// 算法特点分析

public void algorithmCharacteristics() {

System.out.println("标记-整理算法特点:");

System.out.println("1. 不会产生内存碎片");

System.out.println("2. 不需要额外的内存空间");

System.out.println("3. 移动对象需要更新引用");

System.out.println("4. 适合老年代(存活对象多)");

}

// 对象分配

public void allocateObject(int id) {

if (heapSize < heap.length) {

heap[heapSize++] = new MockObject(id, null);

}

}

}

分代收集算法(Generational Collection)

分代收集算法基于对象的存活周期将内存划分为几块,不同区域采用不同的收集算法。

// 分代收集算法实现

public class GenerationalGC {

static class MockObject {

private int id;

private int age = 0;

private MockObject next;

private boolean marked = false;

public MockObject(int id, MockObject next) {

this.id = id;

this.next = next;

}

public int getId() {

return id; }

public int getAge() {

return age; }

public void incrementAge() {

this.age++; }

public MockObject getNext() {

return next; }

public boolean isMarked() {

return marked; }

public void mark() {

this.marked = true; }

}

// 新生代:Eden + 2个Survivor

private MockObject[] eden = new MockObject[100];

private MockObject[] survivorFrom = new MockObject[50];

private MockObject[] survivorTo = new MockObject[50];

// 老年代

private MockObject[] oldGen = new MockObject[1000];

private int edenIndex = 0;

private int survivorFromIndex = 0;

private int survivorToIndex = 0;

private int oldGenIndex = 0;

// Minor GC:新生代收集

public void minorGC() {

System.out.println("Starting Minor GC...");

// 1. 标记新生代中的存活对象

markYoungGeneration();

// 2. 复制存活对象到Survivor区或晋升到老年代

int toPromoteCount = 0;

survivorToIndex = 0;

// 从Eden复制存活对象

for (int i = 0; i < edenIndex; i++) {

if (eden[i] != null && eden[i].isMarked()) {

if (eden[i].getAge() >= 15) {

// 年龄达到阈值,晋升到老年代

oldGen[oldGenIndex++] = eden[i];

toPromoteCount++;

} else {

// 复制到Survivor To区

survivorTo[survivorToIndex++] = eden[i];

eden[i].incrementAge();

}

}

eden[i] = null; // 清空Eden

}

// 从Survivor From复制存活对象

for (int i = 0; i < survivorFromIndex; i++) {

if (survivorFrom[i] != null && survivorFrom[i].isMarked()) {

if (survivorFrom[i].getAge() >= 15) {

oldGen[oldGenIndex++] = survivorFrom[i];

toPromoteCount++;

} else {

survivorTo[survivorToIndex++] = survivorFrom[i];

survivorFrom[i].incrementAge();

}

}

survivorFrom[i] = null; // 清空Survivor From

}

// 交换Survivor区

MockObject[] temp = survivorFrom;

survivorFrom = survivorTo;

survivorTo = temp;

survivorFromIndex = survivorToIndex;

survivorToIndex = 0;

System.out.println("Minor GC completed. Promoted " + toPromoteCount + " objects to old gen.");

}

// Major GC:老年代收集

public void majorGC() {

System.out.println("Starting Major GC...");

// 老年代使用标记-整理算法

markOldGeneration();

compactOldGeneration();

System.out.println("Major GC completed.");

}

// 标记新生代

private void markYoungGeneration() {

// 从GC Roots开始标记

// 这里简化为标记所有对象(实际会更复杂)

for (int i = 0; i < edenIndex; i++) {

if (eden[i] != null) {

eden[i].mark();

}

}

for (int i = 0; i < survivorFromIndex; i++) {

if (survivorFrom[i] != null) {

survivorFrom[i].mark();

}

}

}

// 标记老年代

private void markOldGeneration() {

for (int i = 0; i < oldGenIndex; i++) {

if (oldGen[i] != null) {

oldGen[i].mark();

}

}

}

// 整理老年代

private void compactOldGeneration() {

int toIndex = 0;

for (int i = 0; i < oldGenIndex; i++) {

if (oldGen[i] != null && oldGen[i].isMarked()) {

if (toIndex != i) {

oldGen[toIndex] = oldGen[i];

oldGen[i] = null;

}

toIndex++;

} else if (oldGen[i] != null) {

oldGen[i] = null;

}

}

oldGenIndex = toIndex;

}

// 对象分配

public void allocateObject(int id) {

if (edenIndex < eden.length) {

eden[edenIndex++] = new MockObject(id, null);

} else {

System.out.println("Eden full, triggering Minor GC");

minorGC();

// 重新尝试分配

if (edenIndex < eden.length) {

eden[edenIndex++] = new MockObject(id, null);

} else {

System.out.println("Still no space after GC, promoting to old gen");

oldGen[oldGenIndex++] = new MockObject(id, null);

}

}

}

// 模拟对象年龄增长

public void simulateAging() {

for (int i = 0; i < survivorFromIndex; i++) {

if (survivorFrom[i] != null) {

survivorFrom[i].incrementAge();

}

}

}

}

垃圾收集器

Serial收集器

Serial收集器是最基本的垃圾收集器,使用单线程进行垃圾收集。

// Serial收集器概念演示

public class SerialGCConcept {

// 模拟单线程GC过程

public static class MockSerialGC {

private MockObject[] heap = new MockObject[1000];

private int heapSize = 0;

public void collect() {

System.out.println("Serial GC started - STW (Stop The World)");

// 1. 标记阶段(单线程)

long startTime = System.currentTimeMillis();

markLiveObjects();

long markTime = System.currentTimeMillis() - startTime;

// 2. 清除阶段(单线程)

startTime = System.currentTimeMillis();

sweepDeadObjects();

long sweepTime = System.currentTimeMillis() - startTime;

System.out.println("Serial GC completed. Mark time: " + markTime + "ms, Sweep time: " + sweepTime + "ms");

System.out.println("STW ended");

}

private void markLiveObjects() {

// 从GC Roots开始标记

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null && isLive(heap[i])) {

heap[i].mark();

}

}

}

private void sweepDeadObjects() {

int newHeapSize = 0;

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null && heap[i].isMarked()) {

heap[newHeapSize++] = heap[i];

heap[i].unmark(); // 清除标记

} else if (heap[i] != null) {

heap[i] = null; // 回收死亡对象

}

}

heapSize = newHeapSize;

}

private boolean isLive(MockObject obj) {

// 简化的存活判断

return obj.getId() % 3 != 0; // 假设id不是3的倍数的对象存活

}

}

// Serial收集器特点

public void characteristics() {

System.out.println("Serial收集器特点:");

System.out.println("1. 单线程收集");

System.out.println("2. 简单高效");

System.out.println("3. 适用于客户端模式");

System.out.println("4. 新生代采用复制算法");

System.out.println("5. 老年代采用标记-整理算法");

}

}

ParNew收集器

ParNew收集器是Serial收集器的多线程版本。

// ParNew收集器概念演示

public class ParNewGCConcept {

public static class MockParNewGC {

private MockObject[] heap = new MockObject[1000];

private int heapSize = 0;

private int threadCount = 4;

public void collect() {

System.out.println("ParNew GC started - STW");

// 分区并行处理

int objectsPerThread = heapSize / threadCount;

List> futures = new ArrayList<>();

long startTime = System.currentTimeMillis();

// 并行标记

for (int i = 0; i < threadCount; i++) {

final int start = i * objectsPerThread;

final int end = (i == threadCount - 1) ? heapSize : (i + 1) * objectsPerThread;

CompletableFuture future = CompletableFuture.runAsync(() -> {

for (int j = start; j < end; j++) {

if (heap[j] != null && isLive(heap[j])) {

heap[j].mark();

}

}

});

futures.add(future);

}

// 等待所有线程完成标记

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

long markTime = System.currentTimeMillis() - startTime;

// 串行清理(为简单起见,实际可能并行)

startTime = System.currentTimeMillis();

sweepDeadObjects();

long sweepTime = System.currentTimeMillis() - startTime;

System.out.println("ParNew GC completed. Mark time: " + markTime + "ms, Sweep time: " + sweepTime + "ms");

}

private void sweepDeadObjects() {

int newHeapSize = 0;

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null && heap[i].isMarked()) {

heap[newHeapSize++] = heap[i];

heap[i].unmark();

} else if (heap[i] != null) {

heap[i] = null;

}

}

heapSize = newHeapSize;

}

private boolean isLive(MockObject obj) {

return obj.getId() % 3 != 0;

}

}

// ParNew收集器特点

public void characteristics() {

System.out.println("ParNew收集器特点:");

System.out.println("1. 多线程并行收集");

System.out.println("2. 仅作用于新生代");

System.out.println("3. 配合CMS收集器使用");

System.out.println("4. 默认线程数等于CPU核心数");

}

}

Parallel Scavenge收集器

Parallel Scavenge收集器关注吞吐量。

// Parallel Scavenge收集器概念演示

public class ParallelScavengeGCConcept {

public static class MockParallelScavengeGC {

private MockObject[] heap = new MockObject[1000];

private int heapSize = 0;

private int threadCount = Runtime.getRuntime().availableProcessors();

// 关注吞吐量的参数

private double targetGCTimeRatio = 0.01; // GC时间占比目标

private int maxGCPauseMillis = 200; // 最大暂停时间目标

public void collect() {

System.out.println("Parallel Scavenge GC started");

long startTime = System.currentTimeMillis();

// 并行标记

parallelMark();

// 并行复制

parallelCopy();

long gcTime = System.currentTimeMillis() - startTime;

long totalTime = getRunningTime();

double gcRatio = (double) gcTime / totalTime;

System.out.println("GC ratio: " + gcRatio + ", Target: " + targetGCTimeRatio);

// 根据GC时间比例调整参数

if (gcRatio > targetGCTimeRatio) {

adjustParametersForThroughput();

}

}

private void parallelMark() {

int objectsPerThread = heapSize / threadCount;

List> futures = new ArrayList<>();

for (int i = 0; i < threadCount; i++) {

final int start = i * objectsPerThread;

final int end = (i == threadCount - 1) ? heapSize : (i + 1) * objectsPerThread;

CompletableFuture future = CompletableFuture.runAsync(() -> {

for (int j = start; j < end; j++) {

if (heap[j] != null && isLive(heap[j])) {

heap[j].mark();

}

}

});

futures.add(future);

}

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

}

private void parallelCopy() {

// 并行复制存活对象

List liveObjects = new ArrayList<>();

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null && heap[i].isMarked()) {

liveObjects.add(heap[i]);

heap[i].unmark();

} else if (heap[i] != null) {

heap[i] = null;

}

}

// 重新分配

heapSize = 0;

for (MockObject obj : liveObjects) {

heap[heapSize++] = obj;

}

}

private long getRunningTime() {

// 模拟获取程序运行总时间

return System.currentTimeMillis();

}

private void adjustParametersForThroughput() {

// 根据吞吐量目标调整GC参数

System.out.println("Adjusting parameters for better throughput");

}

private boolean isLive(MockObject obj) {

return obj.getId() % 2 == 0; // 假设偶数ID的对象存活

}

}

// Parallel Scavenge收集器特点

public void characteristics() {

System.out.println("Parallel Scavenge收集器特点:");

System.out.println("1. 关注吞吐量");

System.out.println("2. 自适应调节策略");

System.out.println("3. 新生代并行收集");

System.out.println("4. 适合后台计算服务");

}

}

CMS收集器

CMS(Concurrent Mark Sweep)收集器关注最短回收停顿时间。

// CMS收集器概念演示

public class CMSGCConcept {

public static class MockCMSGC {

private MockObject[] heap = new MockObject[1000];

private int heapSize = 0;

private volatile boolean concurrentMarking = false;

public void collect() {

System.out.println("CMS GC started");

// 1. 初始标记(STW)

long startTime = System.currentTimeMillis();

initialMark();

long initialMarkTime = System.currentTimeMillis() - startTime;

System.out.println("Initial mark completed - STW: " + initialMarkTime + "ms");

// 2. 并发标记(与用户线程并发)

startTime = System.currentTimeMillis();

concurrentMark();

long concurrentMarkTime = System.currentTimeMillis() - startTime;

System.out.println("Concurrent mark completed: " + concurrentMarkTime + "ms");

// 3. 重新标记(STW)

startTime = System.currentTimeMillis();

remark();

long remarkTime = System.currentTimeMillis() - startTime;

System.out.println("Remark completed - STW: " + remarkTime + "ms");

// 4. 并发清除(与用户线程并发)

startTime = System.currentTimeMillis();

concurrentSweep();

long concurrentSweepTime = System.currentTimeMillis() - startTime;

System.out.println("Concurrent sweep completed: " + concurrentSweepTime + "ms");

}

private void initialMark() {

// 仅标记GC Roots直接关联的对象

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null && isGcRoot(heap[i])) {

heap[i].mark();

}

}

}

private void concurrentMark() {

concurrentMarking = true;

// 启动并发标记线程

Thread markThread = new Thread(() -> {

for (int i = 0; i < heapSize && concurrentMarking; i++) {

if (heap[i] != null && !heap[i].isMarked()) {

markReachable(heap[i]);

}

}

});

markThread.start();

// 模拟用户线程继续运行

simulateUserThreads();

try {

markThread.join();

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

concurrentMarking = false;

}

private void remark() {

// 修正并发标记期间对象引用关系变化

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null && hasReferenceChanged(heap[i])) {

markReachable(heap[i]);

}

}

}

private void concurrentSweep() {

// 并发清除死亡对象

Thread sweepThread = new Thread(() -> {

for (int i = 0; i < heapSize; i++) {

if (heap[i] != null && !heap[i].isMarked()) {

heap[i] = null; // 清除死亡对象

} else if (heap[i] != null) {

heap[i].unmark(); // 清除标记

}

}

});

sweepThread.start();

// 用户线程继续运行

simulateUserThreads();

try {

sweepThread.join();

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}

private void markReachable(MockObject obj) {

if (obj != null && !obj.isMarked()) {

obj.mark();

// 标记引用的对象

if (obj.getNext() != null) {

markReachable(obj.getNext());

}

}

}

private boolean isGcRoot(MockObject obj) {

// 简化的GC Root判断

return obj.getId() < 10; // 假设ID小于10的是GC Root

}

private boolean hasReferenceChanged(MockObject obj) {

// 模拟并发标记期间引用关系变化

return Math.random() > 0.9; // 10%概率引用关系变化

}

private void simulateUserThreads() {

// 模拟用户线程在GC期间继续运行

try {

Thread.sleep(100); // 模拟用户线程工作

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}

}

// CMS收集器特点

public void characteristics() {

System.out.println("CMS收集器特点:");

System.out.println("1. 关注最短停顿时间");

System.out.println("2. 基于标记-清除算法");

System.out.println("3. 并发收集,低停顿");

System.out.println("4. 会产生内存碎片");

System.out.println("5. 对CPU资源敏感");

}

}

G1收集器

G1(Garbage-First)收集器面向服务端应用。

// G1收集器概念演示

public class G1GCConcept {

// G1将堆划分为多个Region

public static class Region {

private MockObject[] objects = new MockObject[100];

private int objectCount = 0;

private boolean isHumongous = false; // 是否是大对象Region

private boolean isOld = false; // 是否是老年代Region

public void addObject(MockObject obj) {

if (objectCount < objects.length) {

objects[objectCount++] = obj;

}

}

public int getLiveObjectCount() {

int count = 0;

for (int i = 0; i < objectCount; i++) {

if (objects[i] != null && objects[i].isMarked()) {

count++;

}

}

return count;

}

public boolean isEmpty() {

return objectCount == 0;

}

}

public static class MockG1GC {

private Region[] regions = new Region[200]; // 200个Region

private PriorityQueue collectionSet = new PriorityQueue<>((r1, r2) ->

Integer.compare(r2.getLiveObjectCount(), r1.getLiveObjectCount())); // 按垃圾量排序

public MockG1GC() {

for (int i = 0; i < regions.length; i++) {

regions[i] = new Region();

}

}

public void collect() {

System.out.println("G1 GC started");

// 1. 全局并发标记

concurrentMarking();

// 2. 选择回收价值最大的Region集合

selectCollectionSet();

// 3. 并行回收选定的Region

parallelEvacuation();

}

private void concurrentMarking() {

System.out.println("Concurrent marking phase");

// 并发标记整个堆

for (Region region : regions) {

markRegion(region);

}

}

private void markRegion(Region region) {

// 标记Region中的存活对象

for (int i = 0; i < region.objectCount; i++) {

if (region.objects[i] != null && isLive(region.objects[i])) {

region.objects[i].mark();

}

}

}

private void selectCollectionSet() {

// 选择垃圾最多的Region进行回收

collectionSet.clear();

for (Region region : regions) {

if (!region.isEmpty() && region.getLiveObjectCount() < region.objectCount * 0.8) {

collectionSet.offer(region);

}

}

}

private void parallelEvacuation() {

System.out.println("Parallel evacuation phase");

// 并行回收选中的Region

while (!collectionSet.isEmpty()) {

Region region = collectionSet.poll();

evacuateRegion(region);

}

}

private void evacuateRegion(Region region) {

// 将Region中的存活对象复制到其他Region

List liveObjects = new ArrayList<>();

for (int i = 0; i < region.objectCount; i++) {

if (region.objects[i] != null && region.objects[i].isMarked()) {

liveObjects.add(region.objects[i]);

region.objects[i].unmark();

}

}

// 清空原Region

region.objectCount = 0;

// 将存活对象分配到新的Region

allocateLiveObjects(liveObjects);

}

private void allocateLiveObjects(List liveObjects) {

// 将存活对象分配到合适的Region

for (MockObject obj : liveObjects) {

// 简化的分配逻辑

for (Region region : regions) {

if (region.objectCount < region.objects.length) {

region.addObject(obj);

break;

}

}

}

}

private boolean isLive(MockObject obj) {

return obj.getId() % 3 != 0;

}

}

// G1收集器特点

public void characteristics() {

System.out.println("G1收集器特点:");

System.out.println("1. 面向服务端应用");

System.out.println("2. 并行与并发");

System.out.println("3. 分代收集");

System.out.println("4. 空间整合(类似标记-整理)");

System.out.println("5. 可预测的停顿");

}

}

ZGC收集器

ZGC是JDK 11引入的低延迟垃圾收集器。

// ZGC概念演示(简化版)

public class ZGCConcept {

// ZGC的内存布局概念

public static class ZGCHeap {

// ZGC使用Colored Pointers技术

private static final int MAPPABLE = 0x01; // 可映射

private static final int REMAPPED = 0x02; // 已重映射

private static final int MARKED0 = 0x04; // 标记0

private static final int MARKED1 = 0x08; // 标记1

// 并发标记阶段

public void concurrentMark() {

System.out.println("ZGC Concurrent Mark Phase");

// 使用Colored Pointers进行并发标记

// 不需要STW,用户线程可以继续运行

}

// 并发重映射阶段

public void concurrentRemap() {

System.out.println("ZGC Concurrent Remap Phase");

// 重映射阶段,修正指针

}

// 并发转移阶段

public void concurrentRelocate() {

System.out.println("ZGC Concurrent Relocate Phase");

// 并发转移存活对象到新区域

}

}

// ZGC特点

public void characteristics() {

System.out.println("ZGC收集器特点:");

System.out.println("1. 超低延迟(<10ms)");

System.out.println("2. 并发执行,几乎无停顿");

System.out.println("3. 支持大堆内存(TB级别)");

System.out.println("4. 使用Colored Pointers技术");

System.out.println("5. Region-based内存管理");

}

}

内存调优与监控

内存参数配置

JVM提供了丰富的参数来配置内存区域大小和垃圾收集器。

// 内存参数配置示例

public class MemoryTuningExample {

// 常用JVM参数说明

public void commonJVMParameters() {

System.out.println("常用JVM内存参数:");

System.out.println("-Xms 初始堆大小");

System.out.println("-Xmx 最大堆大小");

System.out.println("-Xmn 新生代大小");

System.out.println("-XX:NewRatio= 新生代与老年代比例");

System.out.println("-XX:SurvivorRatio= Eden区与Survivor区比例");

System.out.println("-XX:MaxTenuringThreshold= 最大年龄阈值");

System.out.println("-XX:+UseSerialGC 使用Serial收集器");

System.out.println("-XX:+UseParNewGC 使用ParNew收集器");

System.out.println("-XX:+UseParallelGC 使用Parallel收集器");

System.out.println("-XX:+UseConcMarkSweepGC 使用CMS收集器");

System.out.println("-XX:+UseG1GC 使用G1收集器");

}

// 内存配置策略

public void memoryConfigurationStrategy() {

System.out.println("内存配置策略:");

System.out.println("1. 根据应用特点选择合适的收集器");

System.out.println("2. 合理设置堆大小,避免频繁GC");

System.out.println("3. 调整新生代大小,平衡Minor GC频率");

System.out.println("4. 监控GC日志,分析性能瓶颈");

}

// GC日志分析

public void gcLogAnalysis() {

System.out.println("GC日志分析要点:");

System.out.println("1. GC频率:Minor GC和Major GC的频率");

System.out.println("2. GC时间:每次GC的停顿时间");

System.out.println("3. 内存使用:各代内存的使用情况");

System.out.println("4. 晋升速率:对象从新生代到老年代的速率");

}

}

内存监控工具

JVM提供了多种工具来监控内存使用情况。

// 内存监控示例

public class MemoryMonitoring {

// 使用ManagementFactory监控内存

public void monitorMemoryUsage() {

MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();

MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();

MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();

System.out.println("Heap Memory Usage:");

System.out.println(" Used: " + heapUsage.getUsed() / (1024 * 1024) + " MB");

System.out.println(" Max: " + heapUsage.getMax() / (1024 * 1024) + " MB");

System.out.println(" Committed: " + heapUsage.getCommitted() / (1024 * 1024) + " MB");

System.out.println("Non-Heap Memory Usage:");

System.out.println(" Used: " + nonHeapUsage.getUsed() / (1024 * 1024) + " MB");

System.out.println(" Max: " + nonHeapUsage.getMax() / (1024 * 1024) + " MB");

System.out.println(" Committed: " + nonHeapUsage.getCommitted() / (1024 * 1024) + " MB");

}

// 监控垃圾收集器信息

public void monitorGarbageCollectors() {

List gcBeans = ManagementFactory.getGarbageCollectorMXBeans();

for (GarbageCollectorMXBean gcBean : gcBeans) {

System.out.println("GC Name: " + gcBean.getName());

System.out.println(" Collection Count: " + gcBean.getCollectionCount());

System.out.println(" Collection Time: " + gcBean.getCollectionTime() + " ms");

String[] memoryPoolNames = gcBean.getMemoryPoolNames();

System.out.println(" Associated Memory Pools: " + String.join(", ", memoryPoolNames));

}

}

// 监控内存池

public void monitorMemoryPools() {

List memoryPoolBeans = ManagementFactory.getMemoryPoolMXBeans();

for (MemoryPoolMXBean poolBean : memoryPoolBeans) {

System.out.println("Memory Pool: " + poolBean.getName());

System.out.println(" Type: " + poolBean.getType());

System.out.println(" Usage: " + poolBean.getUsage());

if (poolBean.getPeakUsage() != null) {

System.out.println(" Peak Usage: " + poolBean.getPeakUsage());

}

}

}

// 模拟内存使用监控

public void simulateMemoryMonitoring() {

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

scheduler.scheduleAtFixedRate(() -> {

monitorMemoryUsage();

System.out.println("---");

}, 0, 5, TimeUnit.SECONDS);

// 模拟内存分配

List memoryHog = new ArrayList<>();

ScheduledExecutorService allocationScheduler = Executors.newScheduledThreadPool(1);

allocationScheduler.scheduleAtFixedRate(() -> {

if (memoryHog.size() < 100) {

memoryHog.add(new byte[1024 * 1024]); // 每次分配1MB

}

}, 0, 100, TimeUnit.MILLISECONDS);

}

}

常见内存问题诊断

了解常见的内存问题及其诊断方法。

// 内存问题诊断示例

public class MemoryProblemDiagnosis {

// 内存泄漏示例

public static class MemoryLeakExample {

private List cache = new ArrayList<>();

public void addToCache(String data) {

// 没有清理机制,可能导致内存泄漏

cache.add(data);

}

// 正确的清理方法

public void clearCache() {

cache.clear();

}

// 使用WeakReference避免内存泄漏

private Map> weakCache = new HashMap<>();

public void addToWeakCache(String key, Object value) {

weakCache.put(key, new WeakReference<>(value));

}

}

// 内存溢出示例

public void demonstrateOutOfMemory() {

List list = new ArrayList<>();

try {

while (true) {

list.add(new byte[1024 * 1024]); // 每次分配1MB

}

} catch (OutOfMemoryError e) {

System.out.println("OutOfMemoryError caught: " + e.getMessage());

list.clear(); // 清理内存

}

}

// 栈溢出示例

public void demonstrateStackOverflow() {

try {

recursiveMethod();

} catch (StackOverflowError e) {

System.out.println("StackOverflowError caught: " + e.getMessage());

}

}

private int recursiveMethod() {

return recursiveMethod() + 1; // 无限递归导致栈溢出

}

// GC开销限制超出示例

public void demonstrateGCOverheadLimit() {

List list = new ArrayList<>();

try {

while (true) {

// 创建大量短生命周期对象

for (int i = 0; i < 1000; i++) {

list.add(new byte[1024]); // 1KB对象

}

// 立即丢弃大部分对象

list.subList(0, 900).clear();

}

} catch (OutOfMemoryError e) {

System.out.println("GC overhead limit exceeded: " + e.getMessage());

}

}

// 内存诊断工具使用

public void diagnosticTools() {

System.out.println("常用内存诊断工具:");

System.out.println("1. jstat - 监控JVM统计信息");

System.out.println("2. jmap - 生成堆转储快照");

System.out.println("3. jhat - 分析堆转储快照");

System.out.println("4. jconsole - 图形化监控工具");

System.out.println("5. VisualVM - 综合性能分析工具");

System.out.println("6. JProfiler - 商业性能分析工具");

System.out.println("7. YourKit - 商业性能分析工具");

}

}

性能调优实践

实际的性能调优案例和最佳实践。

// 性能调优实践示例

public class PerformanceTuningPractice {

// 对象池模式减少GC压力

public static class ObjectPool {

private final Queue pool = new ConcurrentLinkedQueue<>();

private final Supplier factory;

private final Consumer resetter;

public ObjectPool(Supplier factory, Consumer resetter) {

this.factory = factory;

this.resetter = resetter;

}

public T acquire() {

T object = pool.poll();

if (object == null) {

object = factory.get();

}

return object;

}

public void release(T object) {

resetter.accept(object);

pool.offer(object);

}

}

// 字符串池优化

public static class StringPoolOptimization {

private final Map stringPool = new ConcurrentHashMap<>();

public String internString(String str) {

return stringPool.computeIfAbsent(str, s -> s);

}

// 使用String.intern()优化内存

public String useIntern(String str) {

return str.intern(); // 将字符串放入常量池

}

}

// 大对象处理策略

public static class LargeObjectHandling {

// 使用直接内存避免堆内存压力

public ByteBuffer allocateDirectMemory(int size) {

return ByteBuffer.allocateDirect(size); // 直接内存,不受堆大小限制

}

// 分块处理大对象

public void processLargeData(byte[] largeData) {

int chunkSize = 1024 * 1024; // 1MB chunks

for (int i = 0; i < largeData.length; i += chunkSize) {

int end = Math.min(i + chunkSize, largeData.length);

byte[] chunk = Arrays.copyOfRange(largeData, i, end);

processChunk(chunk);

}

}

private void processChunk(byte[] chunk) {

// 处理数据块

}

}

// 引用类型选择

public static class ReferenceTypeSelection {

private Map strongCache = new HashMap<>();

private Map> weakCache = new HashMap<>();

private Map> softCache = new HashMap<>();

// 强引用:对象不会被回收

public void useStrongReference(String key, Object value) {

strongCache.put(key, value);

}

// 软引用:内存不足时会被回收

public void useSoftReference(String key, Object value) {

softCache.put(key, new SoftReference<>(value));

}

// 弱引用:GC时会被回收

public void useWeakReference(String key, Object value) {

weakCache.put(key, new WeakReference<>(value));

}

}

// 性能调优检查清单

public void tuningChecklist() {

System.out.println("JVM性能调优检查清单:");

System.out.println("1. 分析GC日志,确定GC频率和停顿时间");

System.out.println("2. 检查内存使用情况,避免内存泄漏");

System.out.println("3. 选择合适的垃圾收集器");

System.out.println("4. 调整堆大小和各代比例");

System.out.println("5. 优化对象分配和生命周期管理");

System.out.println("6. 使用对象池减少GC压力");

System.out.println("7. 合理使用不同类型的引用");

System.out.println("8. 监控和调优JVM参数");

}

}

JVM内存区域划分和垃圾回收机制是Java程序性能优化的核心。通过深入理解各内存区域的特点、垃圾回收算法的原理和各种收集器的特性,开发者可以更好地进行内存调优,构建高性能的Java应用程序。

关于作者

🌟 我是suxiaoxiang,一位热爱技术的开发者 💡 专注于Java生态和前沿技术分享 🚀 持续输出高质量技术内容

如果这篇文章对你有帮助,请支持一下:

👍 点赞

⭐ 收藏

👀 关注

您的支持是我持续创作的动力!感谢每一位读者的关注与认可!

Copyright © 2088 VR世界杯_世界杯举办 - weiqer.com All Rights Reserved.
友情链接