# Java 性能调优

# 性能基础

# 性能指标

  1. 响应时间

    • 平均响应时间
    • 最大响应时间
    • 百分位响应时间(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);
          }
      }
      
  2. 吞吐量

    • 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;
          }
      }
      
  3. 系统资源

    • 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();
          }
      }
      

# 代码层面优化

# 基本原则

  1. 减少计算

    • 使用缓存
      @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;
          }
      }
      
  2. 减少对象创建

    • 对象池示例:
      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();
      
  3. 合理使用集合

    • 选择合适的集合类型
    • 预设集合初始容量
      // 预设容量避免扩容
      List<String> list = new ArrayList<>(initialCapacity);
      Map<String, String> map = new HashMap<>(initialCapacity, 0.75f);
      

# 数据结构优化

  1. 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");
        }
    }
    
  2. 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启动参数配置

  1. 内存管理参数

    • 堆内存配置
      # 设置初始堆大小
      -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>  # 最大元空间大小
      
  2. 垃圾收集器参数

    • 收集器选择

      # 使用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
      
  3. 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
    
  4. 性能调优参数

    # 指定垃圾收集的并行线程数
    -XX:ParallelGCThreads=n
    
    # 启用/禁用类验证
    -Xverify:none
    
    # 指定编译阈值
    -XX:CompileThreshold=10000
    
    # 设置代码缓存大小
    -XX:ReservedCodeCacheSize=240m
    
    # 启用大页内存
    -XX:+UseLargePages
    
  5. 调试参数

    # 发生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
    
  6. 最佳实践示例

    # 生产环境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"
    
  7. 参数调优建议

    • 堆大小设置

      • 建议将初始堆大小(-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();
            }
        }
    }
    

# 线程池调优

# 最佳实践

  1. 线程池配置示例

    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() // 拒绝策略
            );
        }
    }
    
  2. 监控指标实现

    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);
        }
    }
    

# 数据库调优

# 连接池配置

  1. 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);
        }
    }
    
  2. 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客户端优化

  1. 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();
        }
    }
    
  2. 异步调用示例

    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;
        }
    }