
一台 2G 内存的云服务器要同时跑 Spring Boot 和 MySQL听起来像是个“要不加点钱换个 4G 吧”的劝退配置。但这个组合真的能跑而且能跑得挺稳前提是你别照着大内存服务器的部署套路来。这篇文章我按照自己的实战经历复盘一遍从系统初始化、数据库安装、JVM 参数调整到上线后的内存监控把这条完整链路走下来适合正在用 2C2G 低配云服务器部署个人项目、小体量业务系统的同学参考。整个部署过程里踩过的坑不少尤其是 MySQL 内存占用、Java 进程被内核干掉这类问题我会把当时的判断逻辑和最终参数都写清楚。1. 部署前先算内存账2G 到底够不够用1.1 2G 内存的分配预算2G 内存云服务器实际可用内存是 2048MB但这不是全部都能拿来跑业务。系统自身就要占掉一块我这边装的是精简版 Alibaba Cloud Linux跑起来后 systemd、sshd、crond 这些基础服务加起来占了大约 250MB 到 300MB。也就是说留给 MySQL 和 Java 的可用内存大概只剩 1700MB 左右。我当时的分配预案是这样的MySQL InnoDB 缓冲池给 256MB加上连接线程、排序缓冲、日志缓冲等MySQL 整体占用控制在 450MB 左右Spring Boot 应用这边JVM 堆设置 512MB元空间预留 128MB线程栈、直接内存、网络缓冲等再占 100MB 到 150MBJava 进程整体也就 800MB 上下。这样算下来系统加 MySQL 加 Java 大概 1550MB还剩 500MB 左右给操作系统做 page cache装静态资源和日志缓冲整体不挤。这个预算到底怎么估算出来的我后面会拆开讲。但先说结论2G 内存跑 Spring Boot MySQL 完全可以不过开发环境随便跑没关系生产环境必须对内存支出有清晰认知每一块都得精打细算。1.2 部署方案选型为什么我选择裸机部署而不是 Docker我见过很多教程一上来就docker run mysql、docker run app在 2G 内存的机器上这样玩大概率会出问题。Docker 本身 daemon 要占内存镜像分层、容器日志、数据卷这些机制在低配置机器上会成倍放大排障难度。网上搜“docker 安装 mysql 失败”能找到一大堆案例我身边朋友也实际遇到过容器起不来但宿主机内存明明还有余量的情况排查到最后都是内存预算没算清楚。所以在 2G 内存的场景下我强烈建议裸机部署MySQL 直接装在宿主机上Spring Boot 应用直接用 systemd 托管 Java 进程。不用 Docker 不是因为容器不好而是在内存受限的机器上少一个中间层就少一份不确定开销进程管理和异常排查也更简单直接。对比项裸机部署 systemdDocker Compose 部署额外内存开销无进程直接可见daemon 容器层约 100MB 以上进程管理systemd 托管崩溃自动拉起依赖容器重启策略日志查看journalctl 直接看需要 docker logs 或配置日志驱动故障排查top、free、dmesg 直接定位需要进入容器多一层转化环境隔离性差一些但单机单应用影响不大好但低配下优势不突出软件版本我当时也做了取舍系统用 CentOS 7 兼容系Alibaba Cloud Linux 3JDK 用 11Spring Boot 用 2.7.xMySQL 用 5.7.44。如果项目已经基于 Spring Boot 3.x JDK 17那内存预算要重新调整JDK 17 基础占用会比 JDK 11 高一些但也不是不能跑后面第 4 节我会专门说 MySQL 版本选择的逻辑。2. 从零初始化服务器系统精简与 MySQL 5.7 安装2.1 系统初始化先省掉无用内存拿到一台新的 2G 云服务器第一件事不是急着装 JDK 和 MySQL而是先把系统里用不到的服务关掉。这一步虽然看起来简单但对后续内存控制影响很大。我先执行systemctl list-units --typeservice --staterunning看一下当前有哪些服务在跑。常见可以关闭的包括 postfix这是邮件服务个人项目基本用不到直接systemctl stop postfix systemctl disable postfix。另外如果安全组已经把端口限制好了firewalld 也可以关掉省一点内存和 CPU 开销。不过这个看个人习惯我不建议小白直接关防火墙优先用云厂商的安全组规则控制。然后检查一下当前内存占用大头ps -eo pid,rss,comm --sort-rss | head -n 15 free -h执行完你会看到系统当前真实的占用情况。如果发现某个服务占了几百兆先确认它是不是业务必须的。我有一台机器预装了云监控插件占得不少虽然不是必须但为了方便还是留着了但至少心里有数知道内存被谁吃了。最后把时区改对日志后续排查不犯迷糊timedatectl set-timezone Asia/Shanghai系统初始化到这里就够了。尽量别做无谓的“优化”比如去动内核参数、乱关 journald 之类的容易把系统弄出奇怪问题省那几 MB 内存不值得。2.2 安装 MySQL 5.7.44 的完整过程我这边是全新系统安装前检查了一下有没有预装 MariaDBrpm -qa | grep mariadb如果有先用yum remove清掉不然后续和 MySQL 包冲突会很麻烦。MySQL 5.7.44 是 5.7 系列的最后一个版本也是我在低配机器上推荐的选择。安装方式我建议直接下载官方 RPM 包。先装 MySQL 官方仓库 rpmwget https://repo.mysql.com/mysql57-community-release-el7-11.noarch.rpm rpm -ivh mysql57-community-release-el7-11.noarch.rpm然后安装 serveryum install -y mysql-community-server这一步有两个常见坑。第一是依赖 libaio 缺失报错是mysqld: error while loading shared libraries: libaio.so.1解决办法是yum install -y libaio。第二是安装包下载慢国内云服务器可以配置一下 yum 加速或直接下载 RPM bundle 包本地安装。装完之后重点是初始化。MySQL 5.7 不会自动帮你初始化数据目录必须手动执行mysqld --initialize-insecure --usermysql--initialize-insecure和--initialize的区别在于 root 初始密码。前者 root 是空密码后者会生成随机密码并写到错误日志里。我当时选择了 insecure因为后面还要创建业务账号空密码登录后再改掉就行方便省事。初始化完成后启动systemctl start mysqld systemctl enable mysqld登录并修改 root 密码mysql -uroot ALTER USER rootlocalhost IDENTIFIED BY 这里写你的新密码;接着创建一个业务账号让 Spring Boot 用专门账号连接数据库而不是直接用 root。这里要注意 MySQL 5.7 的密码插件默认是mysql_native_password后面连接基本不会因为认证插件出问题但如果是 8.0默认的caching_sha2_password坑很大下一节细说。创建账号的 SQLCREATE DATABASE IF NOT EXISTS shop_db DEFAULT CHARACTER SET utf8mb4; CREATE USER app_userlocalhost IDENTIFIED BY 这里写应用密码; GRANT ALL PRIVILEGES ON shop_db.* TO app_userlocalhost; FLUSH PRIVILEGES;我特意用了localhost因为应用和数据库在同一台机器上这能降低数据库暴露风险。如果后续需要远程连数据库调试再单独开一个app_user%账号也不迟。2.3 MySQL 8.0 与 5.7 怎么选低配场景的版本对比如果你是新项目大概率会用 MySQL 8.0网上教程也都是 8.0 居多。但我还是要说2G 内存的云服务器跑业务MySQL 5.7.44 比 8.0 稳得多。这不是性能跑分的问题是内存基线的差异。MySQL 8.0 默认配置下的内存占用明显比 5.7 高尤其默认开启的 performance_schema 和更多后台线程在同样 2G 内存的机器上整机内存水位会明显比 5.7 紧张。我实测过 8.0.36 和 5.7.44 在同样配置下部署同一套应用8.0 开启后 free -m 的 available 会低 150MB 左右而且容易出现 swap 波动。另外连接层也有差异。MySQL 8.0 默认认证插件是caching_sha2_password默认开启 SSL这些都会导致 JDBC 连接时报各种奇怪的错误。不是说 8.0 不好而是在低配场景下5.7 省心很多。对比项MySQL 5.7.44MySQL 8.0.x默认内存占用较低缓冲池 128M 起步较高基础组件多默认认证插件mysql_native_passwordcaching_sha2_password默认 SSL可选默认关闭默认开启需显式处理JDBC 连接坑少驱动版本兼容性好多ssl、公钥检索等问题频出功能丰富度相对保守更强窗口函数等更好用低配服务器适配度高一般需要额外调优如果你项目必须用 8.0 提供的新特性那只能硬着头皮调优后面第 4 节我会给出对应的参数调整建议。否则2G 内存场景我真心推荐 5.7.44稳定第一。3. Spring Boot 打包、上传与 JVM 参数调优3.1 Maven 打包与配置文件准备Spring Boot 项目的打包基本就是一件事在 pom.xml 里配好spring-boot-maven-plugin确保打出来的是可执行 jar而不是普通 jar。执行mvn clean package -DskipTests我习惯在 pom.xml 里指定 finalName这样打包出来的文件名固定后续 systemd 脚本不用跟着版本号改build finalNameapp/finalName plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build打包完成后配置文件的准备很关键。低配机器上数据库连接池参数必须要调不能直接用默认值。HikariCP 默认 maximum-pool-size 是 10对 2G 内存来说偏大每多一个连接就多一份 MySQL 线程和 Java 侧的网络缓冲。我把连接池上限压到 5最小空闲 2日常业务完全够用。我的 application.yml 数据源配置大致是spring: datasource: url: jdbc:mysql://127.0.0.1:3306/shop_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: app_user password: ${DB_PASSWORD} hikari: maximum-pool-size: 5 minimum-idle: 2 connection-timeout: 10000 server: port: 8080 management: endpoints: web: exposure: include: health,info注意密码没有写死在配置文件里用的是环境变量DB_PASSWORD。这个细节在 systemd 配置里会体现好处是配置文件可以丢进仓库不泄露密码也方便后续改密。数据库地址我写的是 127.0.0.1因为数据库就在本机没必要走一遍网络协议栈。JDBC URL 里的useSSLfalse和allowPublicKeyRetrievaltrue是为了规避 8.0 时代的 SSL 和公钥检索问题哪怕你用 5.7 加上也没副作用。serverTimezoneAsia/Shanghai则解决时区报错少一个常见坑。上传 jar 包到服务器我习惯先建一个专门运行应用的用户useradd -m appuser mkdir -p /opt/app scp target/app.jar root服务器IP:/tmp/app.jar mv /tmp/app.jar /opt/app/app.jar chown -R appuser:appuser /opt/app用 scp 上传没问题如果用不惯命令行的同学也可以用 WinSCP 这类工具原理一样。3.2 JVM 参数逐个拆解2G 内存下的取舍JVM 参数是这次部署的重头戏。很多教程无脑让人加-XX:UseG1GC但在 2G 内存的机器上G1 的优势完全发挥不出来。G1 有记忆集、写屏障等额外开销堆只有 512MB 时这些机制纯属浪费内存。我实测下来低配场景果断用 Parallel GC 更省内存也更稳。我当时最终用的启动参数是java -server -Xms512m -Xmx512m -XX:MetaspaceSize96m -XX:MaxMetaspaceSize256m \ -XX:UseParallelGC -XX:ParallelGCThreads2 -XX:MaxDirectMemorySize128m \ -Djava.security.egdfile:/dev/./urandom -Dfile.encodingUTF-8 \ -jar /opt/app/app.jar逐个说下这些参数的含义和取舍-Xms512m -Xmx512m堆的初始值和上限都设为 512MB一步到位避免 JVM 在运行过程中动态扩容堆而向系统申请更多内存。低配机器上最忌讳 Xms 和 Xmx 差距过大。-XX:MetaspaceSize96m -XX:MaxMetaspaceSize256m元空间是存类元数据的。Spring Boot 依赖多类也多96MB 起步、256MB 上限是比较合理的配置。太小会导致 Full GC 频繁太大会挤占系统内存。-XX:UseParallelGC低配多核不吃紧的机器上Parallel GC 吞吐量优先内存开销小。JDK 11 默认是 G1所以必须显式指定回 Parallel。-XX:ParallelGCThreads22 核机器上其实默认就是 2但写明更清晰避免 JVM 根据容器环境自动预估线程数出错。-XX:MaxDirectMemorySize128m直接内存是 Netty、Tomcat 等框架会用到的 NIO 缓冲。给 128MB 足够大多数业务使用防止某些框架默认申请过大。-Djava.security.egdfile:/dev/./urandom这个必须加。JDK 在启动时会从/dev/random读取熵来初始化安全随机数如果系统熵不足Spring Boot 启动会卡很久非常像死机。换成/dev/urandom后启动立刻顺畅。我当时的整机内存峰值计算是这样的系统约 300MBMySQL 约 450MBJava 进程约 800MB堆 512MB 元空间 线程栈 直接内存合计约 1550MB剩余 500MB 给系统 page cache。这个比例是经过验证的稳定组合。如果你想给 Java 堆开到 768MBMySQL 缓冲池就得降到 128MB不是不行但整体余量会非常紧OOM 风险上升。3.3 systemd 管理应用进程崩溃自动拉起进程管理我用 systemd理由前面说过简单可靠。在/etc/systemd/system/app.service里写[Unit] DescriptionSpring Boot App Afternetwork.target mysqld.service [Service] Userappuser WorkingDirectory/opt/app EnvironmentDB_PASSWORD你的数据库密码 ExecStart/usr/bin/java -server -Xms512m -Xmx512m -XX:MetaspaceSize96m -XX:MaxMetaspaceSize256m -XX:UseParallelGC -XX:ParallelGCThreads2 -XX:MaxDirectMemorySize128m -Djava.security.egdfile:/dev/./urandom -Dfile.encodingUTF-8 -jar /opt/app/app.jar SuccessExitStatus143 Restartalways RestartSec5 StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target几个关键点EnvironmentDB_PASSWORD...把数据库密码注入应用的环境变量对应 application.yml 里的${DB_PASSWORD}。SuccessExitStatus143是 Stoppable 应用优雅关闭的返回值 143128 15即 SIGTERM。如果不加systemd 会在你执行systemctl stop app时报告失败虽然不影响实际运行但日志里全是红色错误误判率高。Restartalways保证进程崩了自动拉起RestartSec5 是重启间隔防止疯狂重启打满 CPU。日志走 journald可以直接journalctl -u app -f实时看应用日志也可以用journalctl -u app --since 10 min ago拉最近十分钟。写好之后依次执行systemctl daemon-reload systemctl enable app systemctl start app启动后用systemctl status app和journalctl -u app -f确认状态。看到 Tomcat started、Spring Boot 启动完成之类的日志说明应用已经正常起来了。4. MySQL 配置调优2G 内存下的 my.cnf 与连接错误排查4.1 my.cnf 里的关键参数每一条都是为了省内存MySQL 安装好后默认配置是按常规内存机器设计的在 2G 机器上必须自己调。我当时改的是/etc/my.cnf核心配置如下[mysqld] port3306 bind-address127.0.0.1 datadir/var/lib/mysql socket/var/lib/mysql/mysql.sock innodb_buffer_pool_size256M innodb_log_buffer_size8M innodb_log_file_size64M innodb_flush_log_at_trx_commit1 max_connections50 performance_schemaOFF skip-name-resolve table_open_cache256 max_allowed_packet16M逐个解释innodb_buffer_pool_size256M这是 MySQL 内存占用的绝对大头也是性能关键。数据页缓存越大查询越快但内存有限256MB 是 2G 机器上的甜点位。如果业务查询量很大可以看情况升到 384MB但 Java 堆就得压缩到 384MB 左右得权衡。innodb_log_buffer_size8M事务日志缓冲区8MB 对中小业务足够了没必要给 16MB 或更大。innodb_log_file_size64Mredo 日志文件大小。MySQL 默认可能生成较大的 redo 文件每刷一次日志消耗的 IO 和磁盘空间都更多。64MB 比较合适。max_connections50每个连接都要占用线程和缓冲内存默认 151 在低配机器上太浪费了。50 个连接对单体应用足够配合 HikariCP 的 5 个连接完全不会撞上限。performance_schemaOFF这是省内存的一记重拳。Performance Schema 会收集大量细粒度的性能数据内存开销几百 MB 都有可能对低配机器不友好。关闭后你们常用的SHOW PROCESSLIST、EXPLAIN都不受影响只是看不到performance_schema库里的指标对日常运营来说完全可以接受。skip-name-resolve跳过来自客户端 IP 的反向 DNS 解析既能减少连接延迟也能降低解析失败导致连接失败的概率。加了之后授权账号要注意只能用userIP或userlocalhost直接写域名会失效。table_open_cache256表缓存数量调小避免打开太多表描述符占内存。innodb_flush_log_at_trx_commit1每个事务提交都刷盘最安全不会丢数据。在低配机器上性能会有一些损失但个人项目和小业务完全可以接受。千万不要因为想提速就改成 0 或 2断电丢数据的风险不值得。修改配置后重启 MySQLsystemctl restart mysqld重启的时候 InnoDB 可能会做崩溃恢复等十几秒是正常的。修改buffer_pool_size这类参数时务必用SHOW VARIABLES LIKE innodb_buffer_pool_size;确认生效。4.2 JDBC 连接报错SSL 与认证插件高频问题MySQL 连接报错这个坑在低配部署里几乎人人都会遇到。症状大致是应用启动时报Communications link failure、SSL certificate verify failed、Public Key Retrieval is not allowed这类错误。这些报错的原因主要有三个第一是 SSL 默认行为变化。MySQL 8.0 默认开启 SSL而 Connector/J 8.x 驱动默认也是useSSLtrue双方协商后如果证书校验不过连接直接失败。解决方式有两种要么在 JDBC URL 里加useSSLfalse关闭 SSL内网访问场景足够安全要么显式设置useSSLtrueverifyServerCertificatefalse跳过证书校验。前者更简单我推荐前者。第二是caching_sha2_password认证插件。MySQL 8.0 默认的认证插件要求客户端支持公钥检索Connector/J 8.x 会在连接时提示Public Key Retrieval is not allowed解决办法就是 URL 参数里加allowPublicKeyRetrievaltrue或者把账号改回mysql_native_passwordALTER USER app_userlocalhost IDENTIFIED WITH mysql_native_password BY 密码;第三是时区问题。Connector/J 6.0 之后要求显式指定 serverTimezone否则报The server time zone value xxx is unrecognized。解决就是在 URL 里加serverTimezoneAsia/Shanghai。我推荐的 JDBC URL 最终形态就是第 3 节里那个jdbc:mysql://127.0.0.1:3306/shop_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue这里再特别提醒一句如果是 Spring Boot 2.7 之前的项目可能还在用com.mysql.jdbc.Driver新版驱动要改成com.mysql.cj.jdbc.Driver不然启动时也会看到找不到驱动类的报错别忽视这种基础问题。5. 上线验证、监控与内存兜底5.1 健康检查Actuator 和系统层双确认应用启动之后第一件事是验证服务真的可用而不是“日志显示可用”。我用 Spring Boot Actuator 的 health 端点快速验证curl http://127.0.0.1:8080/actuator/health返回{status:UP}说明应用本身起来了。但这个检查其实比较浅我还会再验证一下数据库的真实连通情况。我当时的 health 配置里整合了 DataSource 检查curl 返回包含db节点的状态{status:UP,components:{db:{status:UP,details:{database:MySQL,validationQuery:isValid()}}}}看到 db 也是 UP才能确定连接池到 MySQL 的通路没有问题。如果健康检查失败优先查 MySQL 是不是真的在跑、账号密码是不是注入对了、防火墙/安全组有没有挡住 3306 端口。然后看系统内存的真实表现free -m这里我提醒大家重点看available而不是free。available 表示还能被新进程申请的内存总量包含了可回收的 page cache在 Linux 上这个值才是更真实的可用内存指标。应用运行稳定后内存水位通常会先上涨一阵因为 JVM 堆在慢慢填满然后稳定在-Xmx附近。如果应用是长期涨上去不回头那就要怀疑是不是代码里有内存泄漏得抓堆快照分析了。5.2 OOM Killer 排查与 swap 兜底低配部署最常见的严重事故不是 MySQL 挂了而是 Java 进程“突然消失”。这种情况第一嫌疑就是 OOM Killer。Linux 在内存耗尽时会启动 Out Of Memory Killer 挑进程杀掉Java 进程因为占内存大往往是第一个被选中的对象。判断方法dmesg -T | grep -i killed process如果看到类似Killed process 1234 (java)的输出说明应用确实是被内核杀的。此时的解决办法按优先级排列先把 JVM 堆从 768MB 降回 512MB再检查 MySQL 是不是开太多连接最后才是开 swap 兜底。swap 这块很多人的看法很极端要么建议不开要么建议开很大。我的实际体会是2G 内存机器可以开一个 2G 的 swap但不指望它提升性能只当“保险丝”用防止 OOM Killer 直接秒杀进程让你有时间进服务器处理。配置方法fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo /swapfile none swap sw 0 0 /etc/fstab顺便把系统默认的 swap 倾向调低一点避免内核太积极地把进程内存换到磁盘拖慢整体响应sysctl -w vm.swappiness10 echo vm.swappiness10 /etc/sysctl.conf重点说一句swap 不是救命稻草MySQL 的 InnoDB 缓冲池如果被换出到磁盘查询性能会断崖式下跌。所以 swap 只是能让你有时间优化配置而不是让你可以心安理得地把内存塞爆。5.3 给站点加 HTTPS 可选优化现在新项目基本都有 HTTPS 需求。我这里顺带补充一下低配服务器上接 HTTPS 的轻量做法用 Nginx 反向代理 自动证书签发。Nginx 本身内存占用很低二三十 MB 也能接受。装好 Nginx 后配置一个反代把 443 端口转发到本机 8080server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/privkey.pem; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }证书申请可以直接用 certbot 这类工具自动完成并在 crontab 里加一条自动续期任务。只要域名解析和 80 端口正常一般都能顺利下发证书。加上 HTTPS 之后应用的访问链路从 HTTP 升级成加密传输Spring Boot 应用本身不用改动一行代码反向代理全包了。6. 常见问题速查与最终配置清单6.1 高频问题速查表部署过程中我遇到的典型问题以及身边同事问过的问题整理成了一张速查表按出现频率排序问题现象根本原因解决办法java -jar启动后进程消失dmesg里有 Killed processOOM Killer 杀掉了内存占用最大的 Java 进程降低-Xmx关闭 MySQL 非必要组件开 2G swap 兜底MySQL 启动失败日志提示找不到数据目录5.7 安装后没有手动初始化执行mysqld --initialize-insecure --usermysqlJDBC 报Communications link failure或SSL certificate verify failedMySQL 8.0 默认 SSL 与驱动握手失败JDBC URL 加useSSLfalseJDBC 报Public Key Retrieval is not allowed8.0 的 caching_sha2_password 插件要求公钥检索加allowPublicKeyRetrievaltrue或改用 mysql_native_passwordSpring Boot 启动卡住几分钟没反应JVM 读取/dev/random熵不足启动参数加-Djava.security.egdfile:/dev/./urandom数据库连接数很快耗尽max_connections 默认值太大 / 连接池回收慢MySQL 设max_connections50HikariCP 设maximum-pool-size5systemd 执行 stop 后显示失败应用正常退出码是 143 而不是 0unit 文件加SuccessExitStatus143MySQL 连接时好时坏慢查询时有超时客户端 IP 反查 DNS 导致延迟skip-name-resolve并改用 IP 授权账号这张表基本覆盖了低配服务器部署最常见的处境。遇到问题时我建议按“先看 dmesg、再看 MySQL 错误日志、最后看应用日志”的顺序排查能省很多时间。6.2 最终稳定配置清单如果你不想看前面的分析过程可以直接参考我这套被验证过的最终组合系统Alibaba Cloud Linux 3兼容 CentOS 7 操作习惯关闭 postfix保留 sshdJDKOpenJDK 11Spring Boot2.7.x打成可执行 jar用 systemd 托管MySQL5.7.44innodb_buffer_pool_size256Mperformance_schemaOFFJVM 启动参数-Xms512m -Xmx512m -XX:MetaspaceSize96m -XX:MaxMetaspaceSize256m -XX:UseParallelGC -XX:ParallelGCThreads2连接池HikariCP maximum-pool-size5minimum-idle2Swap2G/swapfileswappiness10监控free -m看 availabledmesg -T | grep -i oom查 OOMActuator health 验证应用状态这套配置下我实际跑了两个业务模块日常内存余量稳定在 400MB 到 500MB没有出现过 Java 进程被内核杀死的情况。如果跑电商大促类高流量场景那肯定不够但作为个人项目、小型团队内部系统、外包演示站完全是能打的配置。6.3 最后分享一点个人经验部署低配服务器这种事真正难的不是某一条命令而是贯穿全程的“内存预算”意识。你装的每一个服务、开的每一个连接、加的每一个参数都在消耗这台机器本来就不宽裕的资源。先保证进程活得下来再谈性能优化这个顺序不要反过来。最后分享一个排查内存问题最好用的组合技。上线前花一分钟执行:free -h ps -eo pid,rss,comm --sort-rss | head -n 15一眼就能看到整机内存剩余和排名前 15 的内存消耗进程。哪个进程内存异常暴涨、系统是不是快触顶了基本不用猜。这个习惯我保留到了现在无论接触新服务器还是排查线上故障都是第一步操作。后续如果遇到内存持续上涨的诡异问题再扔进第三层配合 GC 日志和堆转储分析基本没有查不出来的。