2G内存主机搭建Java网站时,Tomcat与MySQL如何调优避免OOM?

在仅有 2G 内存的主机上搭建 Java 网站,运行 Tomcat + MySQL + Java 应用,资源非常紧张。为了避免 OOM(Out of Memory),必须对 Tomcat 和 MySQL 进行精细化调优,合理分配内存资源。

以下是具体的优化建议:


🔧 一、总体内存规划(2G = 2048MB)

组件 建议内存分配 说明
JVM (Tomcat) 512MB ~ 768MB 避免过大导致系统崩溃
MySQL 512MB ~ 768MB 根据使用场景调整
操作系统 & 其他进程 ≥ 512MB 留给系统缓存、SSH、日志等

⚠️ 总和不要超过 1.5GB,留出缓冲空间防止 swap 频繁或 OOM Killer 干预。


🐱 二、Tomcat 调优(JVM 参数)

1. 设置合理的 JVM 内存参数

编辑 bin/catalina.sh(Linux)或 catalina.bat(Windows),添加:

export JAVA_OPTS="-Xms256m -Xmx512m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"

参数解释:

  • -Xms256m:JVM 初始堆大小,避免频繁扩容。
  • -Xmx512m:最大堆内存,防止占用过多。
  • -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m:控制元空间(替代永久代),防止类加载过多导致 OOM。
  • -XX:+UseG1GC:使用 G1 垃圾回收器,适合小堆且低延迟。
  • -XX:MaxGCPauseMillis=200:目标最大 GC 暂停时间。

✅ 如果应用简单(如单体 Spring Boot 小项目),512MB 堆足够。


2. 减少 Tomcat 自身负载

  • 关闭不必要的 Webapp(如 docs, examples, manager):
    删除 $CATALINA_HOME/webapps/ 下无用目录。
  • 使用轻量级 Connector(NIO):
    server.xml 中确保使用 NIO:
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           executor="tomcatThreadPool"
           protocol="org.apache.coyote.http11.Http11NioProtocol" />
  • 控制线程数(避免线程爆炸):
<Executor name="tomcatThreadPool" namePrefix="http-nio-8080-exec-"
          maxThreads="100" minSpareThreads="10" maxIdleTime="60000"/>

🐬 三、MySQL 调优(重点!默认配置太耗内存)

MySQL 默认配置可能占用 >1GB,必须精简。

编辑 /etc/mysql/my.cnf/etc/my.cnf

[mysqld]
# 基础设置
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# 关键内存参数(总内存控制在 512~768MB)
innodb_buffer_pool_size = 256M     # 最大可设 384M,但 256M 更安全
key_buffer_size = 32M              # MyISAM 索引缓存(若不用 MyISAM 可更小)
query_cache_type = 0                 # 禁用查询缓存(MySQL 8+ 已移除,5.7 可关)
query_cache_size = 0                 # 节省内存
tmp_table_size = 32M
max_heap_table_size = 32M
sort_buffer_size = 512K
read_buffer_size = 512K
read_rnd_buffer_size = 512K
join_buffer_size = 512K
thread_stack = 192K
table_open_cache = 64
table_definition_cache = 400

# 连接相关
max_connections = 50               # 避免连接过多耗内存
thread_cache_size = 4
wait_timeout = 60
interactive_timeout = 60

# 日志(可选关闭以省资源)
# slow_query_log = 0
# log_error_verbosity = 1

# InnoDB 专用
innodb_log_file_size = 48M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 2   # 提升性能,轻微降低持久性
innodb_flush_method = O_DIRECT
innodb_file_per_table = ON

# 字符集
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

✅ 以上配置下,MySQL 内存占用约 300~500MB,适合 2G 主机。


🛠 四、系统级优化

1. 添加 Swap(虚拟内存)

2G 内存建议添加 1~2G Swap,防止 OOM 直接崩溃。

# 创建 2GB swap 文件
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 永久生效(写入 /etc/fstab)
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

⚠️ Swap 不是万能,只是防止 OOM Killer 强杀进程。

2. 监控内存使用

使用命令监控:

free -h
top
htop  # 更直观
jstat -gc <pid>  # 查看 JVM GC 情况

3. 限制后台服务

关闭不需要的服务(如 Apache、Redis、邮件服务等),只保留必要组件。


📈 五、应用层优化(Java 代码层面)

  • 避免内存泄漏:检查静态集合、未关闭流、监听器等。
  • 分页查询大数据:禁止 SELECT * FROM large_table
  • 使用连接池并限制最大连接数(如 HikariCP):
# Spring Boot 示例
spring:
  datasource:
    hikari:
      maximum-pool-size: 10
      minimum-idle: 2
      connection-timeout: 30000
  • 启用缓存(如 Caffeine)减少数据库压力。

✅ 总结:关键点清单

项目 推荐值
JVM 堆内存 -Xms256m -Xmx512m
Metaspace 64m ~ 128m
GC 算法 G1GC
MySQL buffer pool 256M
MySQL max_connections 50
Swap 空间 2GB
Tomcat 线程数 maxThreads=100
禁用 MySQL 查询缓存 query_cache_size=0
监控工具 htop, jstat, free

最终目标
让 Tomcat + MySQL + OS 总内存占用控制在 1.5GB 以内,留出 500MB 缓冲,避免频繁 swap 或 OOM。

如有条件,建议升级到 4G 内存,体验会大幅提升。但在 2G 环境下,以上调优足以支撑小型 Java 网站稳定运行。