ORA-00845错误:别急着改参数,先看看/dev/shm的“家底”
遇到Oracle 11g启动失败,先别一股脑去检查参数文件或者SID配置。很多时候,问题的根源更直接——系统连分配共享内存的空间都没有了。那个经典的ORA-00845: Memory target not supported on this system错误,本质上不是Oracle在“报错”,而是它在“拒绝启动”:数据库读取了memory_target的设置值,一检查/dev/shm(即tmpfs文件系统)的可用空间,发现根本不够,于是直接退出,后续的参数文件它甚至都懒得继续读。
第一步:诊断,确认是“空间不足”还是“配置错误”
看到ORA-00845,第一反应应该是立刻检查/dev/shm的容量。执行命令df -h /dev/shm,如果输出显示只有64M或者一个明显小于你为Oracle设置的memory_target的值,那么问题就找到了。
- 那么,Oracle到底需要多少呢?通过
sqlplus / as sysdba连接(如果实例未启动,可能需要先指定pfile),执行SHOW PARAMETER memory_target和SHOW PARAMETER memory_max_target,取两者中的较大值。这个值(单位是字节)就是你/dev/shm需要满足的底线。 - 这里有个关键点需要厘清:用
ipcs -m查看到的是传统的System V共享内存,它并不占用/dev/shm的空间。真正占用这里的是POSIX共享内存对象,它们在文件系统中表现为/dev/shm/ora_*这类文件。
第二步:调整,为什么“mount -o remount”有时会失灵?
最直接的解决方法是临时调整/dev/shm的大小,例如执行sudo mount -o remount,size=2G /dev/shm。但如果执行后Oracle依然报错,说明调整可能并未真正生效,或者被其他机制覆盖了。
- 首先,用
cat /proc/mounts | grep shm命令验证。确认输出中包含类似size=2097152k(即2G)的条目,而不是原来的size=65536k。 - 在RHEL/CentOS 7及以上版本的系统里,
/dev/shm默认由systemd-tmpfiles管理。这意味着,即使你修改了/etc/fstab,重启后也可能被重置。一个彻底的解决办法是同时执行sudo systemctl mask dev-shm.mount来屏蔽系统的自动管理。 - 某些特定的Oracle Linux发行版可能启用了内核同页合并(KSM, Kernel Samepage Merging)功能,这有时会干扰大页共享内存的分配。可以临时关闭它:
echo 0 | sudo tee /sys/kernel/mm/ksm/run。 - 如果环境是容器(如Docker或Podman),那么在宿主机上调整
/dev/shm对容器内部是完全无效的。必须在启动容器时显式指定共享内存大小,例如使用--shm-size=2G参数。
第三步:排查,谁在悄悄占满/dev/shm?
有时候,/dev/shm的大小是足够的,但在Oracle启动之前,空间已经被其他进程写满了。比如,某个Ja va应用错误地将ja va.io.tmpdir指向了/dev/shm,或者Python多进程留下了残留的/dev/shm/psm_*文件。这会导致Oracle分配内存失败,并且可能只报出模糊的ORA-00845错误,甚至静默退出。
- 可以尝试手动清理(操作需谨慎):
sudo rm -f /dev/shm/ora_* /dev/shm/PostgreSQL.* /dev/shm/redis.*。在删除前,建议用lsof +D /dev/shm检查一下是否有文件正在被使用。 - 查找“罪魁祸首”:运行
ls -lt /dev/shm | head -20,查看最新创建或修改的文件名和时间戳,结合进程名判断来源。 - 对于Ja va应用,必须确保其临时目录
ja va.io.tmpdir没有指向/dev/shm。在Docker中启动Ja va服务时,最佳实践是显式挂载一个独立的临时目录,例如-v /tmp/ja va-tmp:/tmp。 - 建立定时清理机制更为可靠:例如,通过crontab设置每小时执行一次
find /dev/shm -name ".*" -mmin +60 -delete 2>/dev/null,清理60分钟前创建的隐藏临时文件。
说到底,调整/dev/shm的大小只是治标。真正棘手的是在多服务共享的环境中,如何管理好这个公共空间——哪个服务写多了,谁没有及时清理,容器环境下的隔离问题……这些细节如果不盯紧,即使今天把size调到了2G,下周系统照样可能因为空间耗尽而崩溃。
