# Java 性能调优
# 性能基础
# 性能指标
响应时间
- 平均响应时间
- 最大响应时间
- 百分位响应时间(P99、P95)
- 示例监控代码:
public class ResponseTimeMonitor { private final List<Long> responseTimes = new ArrayList<>(); public void recordResponseTime(long startTime) { long responseTime = System.currentTimeMillis() - startTime; responseTimes.add(responseTime); } public double getP99() { Collections.sort(responseTimes); int index = (int) Math.ceil(responseTimes.size() * 0.99) - 1; return responseTimes.get(index); } }
吞吐量
- TPS(每秒事务数)
- QPS(每秒查询数)
- 并发用户数
- 性能测试示例:
public class ThroughputTest { private AtomicLong successCount = new AtomicLong(0); private AtomicLong failCount = new AtomicLong(0); public void recordSuccess() { successCount.incrementAndGet(); } public double getTPS(long durationInSeconds) { return (double) successCount.get() / durationInSeconds; } }
系统资源
- CPU使用率
- 内存使用率
- 磁盘IO
- 网络IO
- 监控代码示例:
public class SystemMonitor { public static double getCpuUsage() { OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); if (osBean instanceof com.sun.management.OperatingSystemMXBean) { return ((com.sun.management.OperatingSystemMXBean) osBean).getSystemCpuLoad(); } return -1; } public static long getUsedMemory() { Runtime runtime = Runtime.getRuntime(); return runtime.totalMemory() - runtime.freeMemory(); } }
# 代码层面优化
# 基本原则
减少计算
- 使用缓存
@Cacheable(value = "userCache", key = "#userId") public User getUser(Long userId) { return userMapper.selectById(userId); }
- 避免重复计算
- 懒加载
public class LazyHolder { private static class Holder { static final ExpensiveObject INSTANCE = new ExpensiveObject(); } public static ExpensiveObject getInstance() { return Holder.INSTANCE; } }
- 使用缓存
减少对象创建
- 对象池示例:
public class ObjectPool<T> { private final Queue<T> pool; private final Supplier<T> creator; public ObjectPool(Supplier<T> creator, int size) { this.creator = creator; this.pool = new ConcurrentLinkedQueue<>(); for (int i = 0; i < size; i++) { pool.offer(creator.get()); } } public T borrow() { T obj = pool.poll(); return obj != null ? obj : creator.get(); } public void release(T obj) { if (obj != null) { pool.offer(obj); } } }
- StringBuilder优化:
// 不推荐 String result = ""; for (int i = 0; i < 100; i++) { result += i; } // 推荐 StringBuilder sb = new StringBuilder(100); for (int i = 0; i < 100; i++) { sb.append(i); } String result = sb.toString();
- 对象池示例:
合理使用集合
- 选择合适的集合类型
- 预设集合初始容量
// 预设容量避免扩容 List<String> list = new ArrayList<>(initialCapacity); Map<String, String> map = new HashMap<>(initialCapacity, 0.75f);
# 数据结构优化
ArrayList vs LinkedList性能对比
public class ListPerformanceTest { private static final int SIZE = 100000; public static void testArrayList() { List<Integer> list = new ArrayList<>(); long start = System.nanoTime(); for (int i = 0; i < SIZE; i++) { list.add(0, i); // 头部插入 } long end = System.nanoTime(); System.out.println("ArrayList插入耗时: " + (end - start) / 1000000.0 + "ms"); } public static void testLinkedList() { List<Integer> list = new LinkedList<>(); long start = System.nanoTime(); for (int i = 0; i < SIZE; i++) { list.add(0, i); // 头部插入 } long end = System.nanoTime(); System.out.println("LinkedList插入耗时: " + (end - start) / 1000000.0 + "ms"); } }
HashMap优化
public class HashMapOptimization { // 预估元素数量 private static final int EXPECTED_SIZE = 100000; // 优化前 Map<String, String> map1 = new HashMap<>(); // 优化后:预设初始容量,避免扩容 Map<String, String> map2 = new HashMap<>((int) (EXPECTED_SIZE / 0.75)); // 使用EntrySet遍历 public void optimizedIteration(Map<String, String> map) { for (Map.Entry<String, String> entry : map.entrySet()) { // 处理entry.getKey()和entry.getValue() } } }
# JVM调优
# JVM启动参数配置
内存管理参数
- 堆内存配置
# 设置初始堆大小 -Xms<size> # 例:-Xms2g # 设置最大堆大小 -Xmx<size> # 例:-Xmx4g # 设置新生代大小 -Xmn<size> # 例:-Xmn1536m -XX:NewSize=<size> # 设置新生代初始大小 -XX:MaxNewSize=<size> # 设置新生代最大大小 # 设置线程栈大小 -Xss<size> # 例:-Xss256k # 设置永久代/元空间大小(JDK8+使用元空间) -XX:MetaspaceSize=<size> # 初始元空间大小 -XX:MaxMetaspaceSize=<size> # 最大元空间大小
- 堆内存配置
垃圾收集器参数
收集器选择
# 使用G1收集器(JDK9+默认) -XX:+UseG1GC # 使用并行收集器 -XX:+UseParallelGC -XX:+UseParallelOldGC # 使用CMS收集器(JDK14中移除) -XX:+UseConcMarkSweepGC # 使用串行收集器 -XX:+UseSerialGC
G1收集器调优
# 设置目标停顿时间 -XX:MaxGCPauseMillis=200 # 设置区域大小(1MB~32MB,必须是2的幂) -XX:G1HeapRegionSize=16m # 设置并发标记阶段的线程数 -XX:ConcGCThreads=n # 设置混合垃圾回收周期中要包含的旧区域的占比 -XX:G1MixedGCLiveThresholdPercent=65
GC日志参数
# JDK9之前的GC日志参数 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc.log # JDK9及以后的统一日志系统 -Xlog:gc*:file=/path/to/gc.log:time,uptime:filecount=5,filesize=100m
性能调优参数
# 指定垃圾收集的并行线程数 -XX:ParallelGCThreads=n # 启用/禁用类验证 -Xverify:none # 指定编译阈值 -XX:CompileThreshold=10000 # 设置代码缓存大小 -XX:ReservedCodeCacheSize=240m # 启用大页内存 -XX:+UseLargePages
调试参数
# 发生OOM时导出堆转储文件 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump.hprof # JIT编译器日志 -XX:+PrintCompilation # 类加载详细信息 -XX:+TraceClassLoading -XX:+TraceClassUnloading # 启用远程调试 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
最佳实践示例
# 生产环境JVM配置示例 JAVA_OPTS=" -Xms4g -Xmx4g -Xmn1536m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m -Xlog:gc*:file=./logs/gc-%t.log:time,uptime:filecount=5,filesize=100m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./logs/dump.hprof -XX:+DisableExplicitGC -XX:+PrintTenuringDistribution" # 开发环境JVM配置示例 JAVA_OPTS=" -Xms1g -Xmx1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -XX:+UseG1GC -Xlog:gc*:file=./logs/gc.log:time -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
参数调优建议
堆大小设置
- 建议将初始堆大小(-Xms)与最大堆大小(-Xmx)设置为相同值,避免堆大小调整导致的性能开销
- 新生代大小(-Xmn)建议占堆大小的1/3到1/2
GC选择
- 对于大内存(4G以上)的应用,建议使用G1收集器
- 对于小内存(4G以下)的应用,可以考虑使用并行收集器
- 对于需要低延迟的应用,可以考虑使用ZGC(JDK11+)
监控建议
- 在生产环境中始终开启GC日志
- 配置OOM时的堆转储
- 合理设置元空间大小,避免动态调整
日志分析示例:
public class GCLogAnalyzer { public static void analyzeGCLog(String logPath) { try (BufferedReader reader = new BufferedReader(new FileReader(logPath))) { String line; while ((line = reader.readLine()) != null) { if (line.contains("[GC (Allocation Failure)")) { // 分析Minor GC parseMinorGC(line); } else if (line.contains("[Full GC")) { // 分析Full GC parseFullGC(line); } } } catch (IOException e) { e.printStackTrace(); } } }
# 线程池调优
# 最佳实践
线程池配置示例
public class ThreadPoolConfig { public ThreadPoolExecutor createThreadPool() { int processors = Runtime.getRuntime().availableProcessors(); return new ThreadPoolExecutor( processors, // 核心线程数 processors * 2, // 最大线程数 60L, // 空闲线程存活时间 TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), // 工作队列 new ThreadFactoryBuilder().setNameFormat("custom-pool-%d").build(), new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略 ); } }
监控指标实现
public class ThreadPoolMonitor { private ThreadPoolExecutor executor; public ThreadPoolStats getStats() { return new ThreadPoolStats( executor.getActiveCount(), executor.getPoolSize(), executor.getQueue().size(), executor.getCompletedTaskCount() ); } @Scheduled(fixedRate = 60000) public void monitorThreadPool() { ThreadPoolStats stats = getStats(); log.info("Thread Pool Stats: {}", stats); } }
# 数据库调优
# 连接池配置
HikariCP配置示例
@Configuration public class DataSourceConfig { @Bean public HikariDataSource dataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/test"); config.setUsername("root"); config.setPassword("password"); config.setMinimumIdle(10); config.setMaximumPoolSize(50); config.setIdleTimeout(300000); config.setConnectionTimeout(20000); config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); return new HikariDataSource(config); } }
SQL优化示例
-- 优化前 SELECT * FROM users WHERE name LIKE '%张%'; -- 优化后 SELECT id, name, age FROM users WHERE name_pinyin LIKE 'zhang%' AND name LIKE '%张%'; -- 分页优化 SELECT id, name FROM users WHERE id > last_id ORDER BY id ASC LIMIT 20;
# 网络调优
# HTTP客户端优化
OkHttp配置示例
public class HttpClientConfig { public OkHttpClient createHttpClient() { return new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .connectionPool(new ConnectionPool(50, 5, TimeUnit.MINUTES)) .dispatcher(new Dispatcher(threadPoolExecutor)) .build(); } }
异步调用示例
public class AsyncHttpClient { private final OkHttpClient client; public CompletableFuture<String> asyncGet(String url) { CompletableFuture<String> future = new CompletableFuture<>(); Request request = new Request.Builder().url(url).build(); client.newCall(request).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { try { future.complete(response.body().string()); } catch (IOException e) { future.completeExceptionally(e); } } @Override public void onFailure(Call call, IOException e) { future.completeExceptionally(e); } }); return future; } }