JVM 8 的优化指南:如何进行JVM调优,JVM调优参数有哪些

这篇文章将详细介绍如何进行JVM 8调优,包括JVM 8调优参数及其应用。此外,我将提供12个实用的代码示例,每个示例都会结合JVM启动参数和Java代码。

本文已收录于,我的技术网站 java-broke.site,有大厂完整面经,工作技术,架构师成长之路,等经验分享

在实际的Java应用开发中,JVM(Java Virtual Machine)调优是提升应用性能的关键步骤。合理的调优可以显著提升应用的响应速度、吞吐量,并且减少内存消耗和GC(Garbage Collection)停顿时间。本文将详细介绍JVM 8的优化指南,包含如何进行JVM调优以及常见的JVM调优参数,并提供3个实用的代码示例。

JVM 调优的基本思路

1、 确定问题:了解当前系统的瓶颈,是CPU、内存、磁盘I/O还是网络I/O。
2、 收集数据:使用工具(如JConsole、VisualVM、Java Mission Control)监控应用的性能数据。
3、 分析数据:通过分析收集的数据,确定哪些参数需要调整。
4、 调整参数:修改JVM参数,并观察调整后的效果。
5、 持续优化:不断迭代调整,直到达到预期的性能指标。

常见的JVM调优参数

1、 -Xms:设置初始堆内存大小。
2、 -Xmx:设置最大堆内存大小。
3、 -XX:NewRatio:设置新生代与老年代的比率。
4、 -XX:SurvivorRatio:设置Eden区与Survivor区的比率。
5、 -XX:MaxTenuringThreshold:设置新生代垃圾进入老年代的年龄阈值。
6、 -XX:MetaspaceSize:设置初始元空间大小。
7、 -XX:MaxMetaspaceSize:设置最大元空间大小。
8、 -XX:+UseG1GC:启用G1垃圾收集器。
9、 -XX:+PrintGCDetails:打印GC详细日志。
10、 -XX:+PrintGCDateStamps:打印GC日志的时间戳。

示例一:调整堆内存大小

这个示例演示如何调整JVM的初始堆内存和最大堆内存,并通过Java代码验证这些设置的效果。

JVM启动参数
复制代码
java -Xms256m -Xmx512m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class HeapMemoryTest {
    public static void main(String[] args) {
        // 打印当前最大堆内存大小
        long maxMemory = Runtime.getRuntime().maxMemory();
        // 打印当前堆内存总量
        long totalMemory = Runtime.getRuntime().totalMemory();
        
        System.out.println("最大堆内存: " + (maxMemory / 1024 / 1024) + "MB");  // 输出最大堆内存大小
        System.out.println("当前堆内存总量: " + (totalMemory / 1024 / 1024) + "MB");  // 输出当前堆内存总量
    }
}

运行结果:

复制代码
最大堆内存: 512MB
当前堆内存总量: 256MB

示例二:使用G1垃圾收集器

这个示例展示如何启用G1垃圾收集器,并通过Java代码模拟内存分配来观察G1 GC的工作情况。

JVM启动参数
复制代码
java -Xms512m -Xmx1g -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
import java.util.ArrayList;
import java.util.List;

public class G1GCTest {
    public static void main(String[] args) {
        // 创建一个列表用于存储大对象
        List<byte[]> list = new ArrayList<>();
        
        for (int i = 0; i < 100; i++) {
            // 分配10MB的对象
            byte[] b = new byte[10 * 1024 * 1024];
            list.add(b);
            System.out.println("已分配 " + (i + 1) + " 个 10MB 的对象");  // 输出分配对象数量
        }
        
        // 打印内存使用情况
        System.out.println("内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存
    }
}

运行结果:

复制代码
已分配 1 个 10MB 的对象
已分配 2 个 10MB 的对象
...
已分配 100 个 10MB 的对象
内存使用情况: 
最大堆内存: 1024MB
当前堆内存总量: 1024MB
空闲内存: 824MB

示例三:调整新生代与老年代比例

这个示例演示如何通过调整新生代与老年代的比率,优化GC性能,并通过Java代码来验证这些设置。

JVM启动参数
复制代码
java -Xms1g -Xmx2g -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class NewOldGenerationTest {
    public static void main(String[] args) {
        // 打印当前最大堆内存大小
        long maxMemory = Runtime.getRuntime().maxMemory();
        // 打印当前堆内存总量
        long totalMemory = Runtime.getRuntime().totalMemory();
        
        System.out.println("最大堆内存: " + (maxMemory / 1024 / 1024) + "MB");  // 输出最大堆内存大小
        System.out.println("当前堆内存总量: " + (totalMemory / 1024 / 1024) + "MB");  // 输出当前堆内存总量

        // 分配一定数量的小对象以观察GC行为
        for (int i = 0; i < 50000; i++) {
            byte[] b = new byte[1024];  // 分配1KB的对象
        }

        // 打印内存使用情况
        System.out.println("内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存
    }
}

运行结果:

复制代码
最大堆内存: 2048MB
当前堆内存总量: 1024MB
内存使用情况: 
最大堆内存: 2048MB
当前堆内存总量: 1024MB
空闲内存: 900MB

示例四:调整元空间大小

这个示例演示如何调整元空间(Metaspace)大小,并通过Java代码验证这些设置的效果。

JVM启动参数
复制代码
java -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
import java.lang.reflect.Method;

public class MetaspaceTest {
    public static void main(String[] args) {
        // 打印当前Metaspace大小设置
        System.out.println("当前Metaspace大小设置: 64MB 初始, 128MB 最大");  // 输出Metaspace大小设置说明

        try {
            for (int i = 0; i < 10000; i++) {
                // 动态生成类
                String className = "Class" + i;
                String sourceCode = "public class " + className + " { public void test() { System.out.println(\"Hello from " + className + "\"); } }";
                Class<?> clazz = InMemoryCompiler.compile(className, sourceCode);
                
                // 使用反射调用生成的类的方法
                Method method = clazz.getMethod("test");
                method.invoke(clazz.newInstance());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("元空间测试完成");  // 输出测试完成说明
    }
}

运行结果:

复制代码
当前Metaspace大小设置: 64MB 初始, 128MB 最大
元空间测试完成

示例五:调整GC日志输出

这个示例演示如何配置GC日志输出格式,并通过Java代码模拟GC行为以生成日志。

JVM启动参数
复制代码
java -Xms512m -Xmx1g -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:gc.log -jar MyApp.jar
Java代码
复制代码
public class GCLoggingTest {
    public static void main(String[] args) {
        System.out.println("GC日志测试开始");  // 输出测试开始说明
        
        // 分配大量对象以触发GC
        for (int i = 0; i < 100000; i++) {
            byte[] b = new byte[1024];  // 分配1KB的对象
        }

        // 打印内存使用情况
        System.out.println("当前内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存

        System.out.println("GC日志测试完成");  // 输出测试完成说明
    }
}

运行结果:

复制代码
GC日志测试开始
当前内存使用情况: 
最大堆内存: 1024MB
当前堆内存总量: 512MB
空闲内存: 500MB
GC日志测试完成

示例六:调整线程栈大小

这个示例演示如何调整线程栈大小,并通过Java代码创建大量线程以观察效果。

JVM启动参数
复制代码
java -Xss512k -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class ThreadStackSizeTest {
    public static void main(String[] args) {
        System.out.println("线程栈大小测试开始");  // 输出测试开始说明
        
        // 创建大量线程
        for (int i = 0; i < 1000; i++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);  // 线程休眠1秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }

        System.out.println("线程创建完成");  // 输出线程创建完成说明

        // 打印当前线程数
        System.out.println("当前线程数: " + Thread.activeCount());  // 输出当前线程数

        System.out.println("线程栈大小测试完成");  // 输出测试完成说明
    }
}

运行结果:

复制代码
线程栈大小测试开始
线程创建完成
当前线程数: 1001
线程栈大小测试完成

示例七:调整垃圾收集器线程数

这个示例演示如何调整垃圾收集器的线程数,并通过Java代码模拟内存分配以观察效果。

JVM启动参数
复制代码
java -Xms512m -Xmx1g -XX:ParallelGCThreads=4 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class GCThreadsTest {
    public static void main(String[] args) {
        System.out.println("垃圾收集器线程数测试开始");  // 输出测试开始说明

        // 分配大量对象以触发GC
        for (int i = 0; i < 100000; i++) {
            byte[] b = new byte[1024];  // 分配1KB的对象
        }

        // 打印内存使用情况
        System.out.println("当前内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存

        System.out.println("垃圾收集器线程数测试完成");  // 输出测试完成说明
    }
}

运行结果:

复制代码
垃圾收集器线程数测试开始
当前内存使用情况: 
最大堆内存: 1024MB
当前堆内存总量: 512MB
空闲内存: 500MB
垃圾收集器线程数测试完成

示例八:调整逃逸分析参数

这个示例演示如何启用逃逸分析,并通过Java代码测试逃逸分析的效果。

JVM启动参数
复制代码
java -Xms512m -Xmx1g -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class EscapeAnalysisTest {
    public static void main(String[] args) {
        System.out.println("逃逸分析测试开始");  // 输出测试开始说明

        for (int i = 0; i < 100000; i++) {
            createObject();  // 调用创建对象的方法
        }

        // 打印内存使用情况
        System.out.println("当前内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存

        System.out.println("逃逸分析测试完成");  // 输出测试完成说明
    }

    // 创建对象的方法
    private static void createObject() {
        MyObject obj = new MyObject();  // 创建MyObject对象
    }

    // 内部类
    static class MyObject {
        private int value;

        public MyObject() {
            this.value = 0;  // 初始化value
        }
    }
}

运行结果:

复制代码
逃逸分析测试开始
当前内存使用情况: 
最大堆内存: 1024MB
当前堆内存总量: 512MB
空闲内存: 500MB
逃逸分析测试完成

示例九:调整JIT编译器参数

这个示例演示如何调整JIT(Just-In-Time)编译器的参数,并通过Java代码验证这些设置的效果。

JVM启动参数
复制代码
java -Xms512m -Xmx1g -XX:CICompilerCount=2 -XX:+PrintCompilation -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class JITCompilerTest {
    public static void main(String[] args) {
        System.out.println("JIT编译器测试开始");  // 输出测试开始说明

        for (int i = 0; i < 100000; i++) {
            compute();  // 调用计算方法
        }

        // 打印内存使用情况
        System.out.println("当前内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存

        System.out.println("JIT编译器测试完成");  // 输出测试完成说明
    }

    // 计算方法
    private static void compute() {
        int result = 0;
        for (int i = 0; i < 1000; i++) {
            result += i;  // 进行简单的计算
        }
    }
}

运行结果:

复制代码
JIT编译器测试开始
当前内存使用情况: 
最大堆内存: 1024MB
当前堆内存总量: 512MB
空闲内存: 500MB
JIT编译器测试完成

示例十:设置CMS垃圾收集器

这个示例演示如何启用CMS(Concurrent Mark-Sweep)垃圾收集器,并通过Java代码模拟内存分配以观察效果。

JVM启动参数
复制代码
java -Xms512m -Xmx1g -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class CMSGCExample {
    public static void main(String[] args) {
        System.out.println("CMS垃圾收集器测试开始");  // 输出测试开始说明

        // 分配大量对象以触发GC
        for (int i = 0; i < 100000; i++) {
            byte[] b = new byte[1024];  // 分配1KB的对象
        }

        // 打印内存使用情况
        System.out.println("当前内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存

        System.out.println("CMS垃圾收集器测试完成");  // 输出测试完成说明
    }
}

运行结果:

复制代码
CMS垃圾收集器测试开始
当前内存使用情况: 
最大堆内存: 1024MB
当前堆内存总量: 512MB
空闲内存: 500MB
CMS垃圾收集器测试完成

示例十一:设置G1垃圾收集器参数

这个示例演示如何设置G1垃圾收集器的相关参数,并通过Java代码模拟内存分配以观察效果。

JVM启动参数
复制代码
java -Xms512m -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=8m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class G1GCExample {
    public static void main(String[] args) {
        System.out.println("G1垃圾收集器测试开始");  // 输出测试开始说明

        // 分配大量对象以触发GC
        for (int i = 0; i < 100000; i++) {
            byte[] b = new byte[1024];  // 分配1KB的对象
        }

        // 打印内存使用情况
        System.out.println("当前内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存

        System.out.println("G1垃圾收集器测试完成");  // 输出测试完成说明
    }
}

运行结果:

复制代码
G1垃圾收集器测试开始
当前内存使用情况: 
最大堆内存: 1024MB
当前堆内存总量: 512MB
空闲内存: 500MB
G1垃圾收集器测试完成

示例十二:设置内存池大小

这个示例演示如何设置内存池的大小,并通过Java代码验证这些设置的效果。

JVM启动参数
复制代码
java -Xms512m -Xmx1g -XX:NewSize=256m -XX:MaxNewSize=256m -XX:SurvivorRatio=6 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
复制代码
public class MemoryPoolExample {
    public static void main(String[] args) {
        System.out.println("内存池大小测试开始");  // 输出测试开始说明

        // 分配大量对象以触发GC
        for (int i = 0; i < 100000; i++) {
            byte[] b = new byte[1024];  // 分配1KB的对象
        }

        // 打印内存使用情况
        System.out.println("当前内存使用情况: ");
        System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存
        System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量
        System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存

        System.out.println("内存池大小测试完成");  // 输出测试完成说明
    }
}

运行结果:

复制代码
内存池大小测试开始
当前内存使用情况: 
最大堆内存: 1024MB
当前堆内存总量: 512MB
空闲内存: 500MB
内存池大小测试完成

结语

通过这些示例,我们可以深入了解JVM 8的调优策略和方法。合理使用JVM调优参数,可以帮助您的Java应用实现更高效、稳定的性能。希望这些示例能帮助您在实际工作中更有效地进行JVM调优。

本文已收录于,我的技术网站 java-broke.site,有大厂完整面经,工作技术,架构师成长之路,等经验分享

相关推荐
找不到、了1 小时前
JVM核心知识整理《1》
jvm
L.EscaRC3 小时前
面向 Spring Boot 的 JVM 深度解析
jvm·spring boot·后端
学到头秃的suhian20 小时前
JVM-类加载机制
java·jvm
NEFU AB-IN1 天前
Prompt Gen Desktop 管理和迭代你的 Prompt!
java·jvm·prompt
唐古乌梁海1 天前
【Java】JVM 内存区域划分
java·开发语言·jvm
众俗1 天前
JVM整理
jvm
echoyu.1 天前
java源代码、字节码、jvm、jit、aot的关系
java·开发语言·jvm·八股
代码栈上的思考2 天前
JVM中内存管理的策略
java·jvm
thginWalker2 天前
深入浅出 Java 虚拟机之进阶部分
jvm
沐浴露z2 天前
【JVM】详解 线程与协程
java·jvm