Java性能优化是一个复杂的主题,涉及代码层面的优化、JVM调优以及系统架构的改进。本文将深入探讨Java性能优化的各个方面,并提供实用的调优建议。
1. JVM内存模型
1.1 内存分区
1
2
3
|
// JVM参数配置示例
-Xms2g -Xmx4g -XX:NewRatio=2 -XX:SurvivorRatio=8
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
|
内存分配示意:
1
2
3
4
5
6
7
8
9
|
堆空间(Heap):
- 新生代(Young Generation)
- Eden区
- Survivor区(From和To)
- 老年代(Old Generation)
非堆空间:
- 元空间(Metaspace)
- 代码缓存
- 线程栈
|
2. GC优化
2.1 GC参数配置
1
2
3
4
5
6
7
8
9
|
# CMS垃圾收集器配置
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
# G1垃圾收集器配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=16m
|
2.2 GC日志分析
1
2
3
4
|
# 开启GC日志
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/path/to/gc.log
|
3. 代码层面优化
3.1 字符串优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class StringOptimization {
public String concatenate(List<String> strings) {
// 不推荐
String result = "";
for (String s : strings) {
result += s; // 每次都创建新对象
}
// 推荐
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append(s);
}
return sb.toString();
}
}
|
3.2 集合优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class CollectionOptimization {
// 初始化时指定容量
List<String> list = new ArrayList<>(10000);
// 使用批量操作
public void batchProcess(List<String> items) {
// 不推荐
for (String item : items) {
list.add(item);
}
// 推荐
list.addAll(items);
}
}
|
4. 线程池优化
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
|
public class ThreadPoolOptimization {
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
10, // 核心线程数
20, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1000), // 工作队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
public void submitTask(Runnable task) {
executor.submit(task);
}
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
|
5. 数据库访问优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class DatabaseOptimization {
// 使用批量操作
public void batchInsert(List<User> users) {
jdbcTemplate.batchUpdate(
"INSERT INTO users (name, email) VALUES (?, ?)",
new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i)
throws SQLException {
User user = users.get(i);
ps.setString(1, user.getName());
ps.setString(2, user.getEmail());
}
@Override
public int getBatchSize() {
return users.size();
}
}
);
}
}
|
6. JVM监控工具
6.1 JVisualVM配置
1
2
3
4
5
|
# 启动JVisualVM并开启远程监控
jvisualvm -J-Dcom.sun.management.jmxremote
-J-Dcom.sun.management.jmxremote.port=3333
-J-Dcom.sun.management.jmxremote.ssl=false
-J-Dcom.sun.management.jmxremote.authenticate=false
|
6.2 Arthas使用
1
2
3
4
5
6
7
8
|
# 启动Arthas
java -jar arthas-boot.jar
# 常用命令
dashboard # 系统整体情况
thread # 线程信息
heapdump # 导出堆信息
trace # 方法调用追踪
|
7. 内存泄漏排查
7.1 常见内存泄漏场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class MemoryLeakExample {
private static final Map<String, Object> cache = new HashMap<>();
// 可能导致内存泄漏的代码
public void addToCache(String key, Object value) {
cache.put(key, value); // 没有清理机制
}
// 改进版本
private static final Map<String, Object> improvedCache =
new WeakHashMap<>();
public void addToImprovedCache(String key, Object value) {
improvedCache.put(key, value); // 使用WeakHashMap
}
}
|
7.2 使用MAT分析
1
2
3
4
5
6
7
|
# 生成堆转储文件
jmap -dump:format=b,file=heap.bin <pid>
# 使用MAT分析
# 1. 查看内存泄漏嫌疑对象
# 2. 分析对象引用链
# 3. 定位泄漏源
|
8. 性能测试
1
2
3
4
5
6
7
8
9
|
@Test
public void performanceTest() {
long start = System.nanoTime();
// 执行待测试代码
long end = System.nanoTime();
System.out.printf("执行时间: %d ms%n",
TimeUnit.NANOSECONDS.toMillis(end - start));
}
|
最佳实践建议
- 合理配置JVM参数
- 定期进行GC日志分析
- 使用性能监控工具
- 及时排查内存泄漏
- 优化代码和SQL查询
性能优化清单
- JVM参数优化
1
2
3
4
5
6
7
8
9
10
11
|
# 生产环境推荐配置
-server
-Xms4g
-Xmx4g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dump
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/path/to/gc.log
|
- 代码优化
1
2
3
4
5
|
// 1. 使用StringBuilder而不是String连接
// 2. 使用批量操作而不是循环单个操作
// 3. 使用并发集合而不是同步集合
// 4. 使用局部变量而不是类变量
// 5. 及时释放资源
|
总结
Java性能优化是一个持续的过程,需要从多个层面进行优化。通过合理的JVM配置、代码优化、数据库优化等手段,可以显著提升应用性能。建议建立性能监控体系,及时发现和解决性能问题。