十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Windows Oracle内存占用优化:定位ORCL服务与SGA/PGA调参

Windows Oracle内存占用优化:定位ORCL服务与SGA/PGA调参 1. 先搞明白那台机器上的内存到底被谁吃了1.1 你搜的OracleServerOral其实是哪个服务先把名字这事说清楚。搜索框里敲OracleServerOral的人十个里有八个是想找OracleServiceORCL这个服务。Oral、ORCL 一字之差多半是拼写记忆串了。ORCL 是安装时默认的实例 SIDSystem Identifier实例标识你装库的时候如果自定义成ORCL、XE、PROD之类显示出来的服务名就会跟着变比如OracleServiceXE、OracleServicePROD。所以看到别人截图写 ORCL 而自己机器上是别的名字别慌是同一个东西只是 SID 不同。这个服务是整台机器上 Oracle 内存占用的绝对主力。它的定位是实例进程的宿主——Windows 上没有 Linux 那种 fork 出几十个后台进程的做法Oracle 把 SMON、PMON、DBWn、LGWR、CKPT 这些后台进程全塞进一个oracle.exe里用线程来实现这个 exe 所在的宿主服务就是OracleServiceSID。SGASystem Global Area就是挂在这个进程下面的一块共享内存。你在任务管理器里看到oracle.exe占了 2GB、4GB 甚至更多绝大部分就是 SGA 的账。而OracleOraDb11g_home1TNSListener这类监听服务实际吃的内存通常只有几 MB 到几十 MB跟实例服务完全不是一个量级。很多人一刀切地把监听也当成内存杀手其实搞错了对象。真正需要动手的永远是那个带 SID 后缀的实例服务。先认准目标再谈优化这是我踩过最多次的坑。1.2 一个实例在Windows上到底起了多少个服务装一次 OracleWindows 服务列表里会冒出一串东西名字都长得像很容易让人头皮发麻。我把常见的几个列一下顺便标注哪些能关、哪些千万别动服务名作用内存量级能否关停OracleServiceORCL实例本体SGA 宿主几百 MB 到数 GB不能这是核心OracleOraDb11g_home1TNSListener监听器接受客户端连接10-50MB开发机可临时关但关了就连不上OracleOraDb11g_home1ClrAgent.NET 存储过程扩展宿主20-80MB不用 .NET 存储过程可关OracleJobSchedulerORCL数据库内部作业调度20-60MB可关改手动OracleDBConsoleorcl基于 Java 的 EM 网页控制台200-500MB开发机基本可关OracleVssWriterORCL卷影复制备份支持10-30MB不做 VSS 备份可关OracleMTSRecoveryService分布式事务恢复10-20MB不用 MTS 可关这张表建议你对着自己机器的服务列表核一遍。OracleDBConsoleorcl是我见过最冤大头的一个它本质是个跑在 Tomcat 上的 Java 应用一个开发机上没人访问的 EM 页面常年稳定吃 300MB 上下而且崩了还会反复重启。ClrAgent和JobSchedulerORCL加起来又能省 100MB 出头。1.3 为什么任务管理器显示的数和参数对不上这是最容易让人误判的地方必须单独拎出来讲。你在 SQL 里执行show parameter sga_target看到 1.5G回头在任务管理器里看到oracle.exe占 3.2G然后就懵了到底谁在骗我两个都不算骗你只是口径不同。SGA 在 Windows 上通过内存映射文件实现任务管理器的工作集Working Set统计的是进程被访问过的物理页包含了 SGA 里那些被加载过的部分、PGAProgram Global Area的私有内存、代码段、以及各种堆。而sga_target只是 SGA 的目标大小不是全部占用。完整的账大概是这样SGA由sga_target/sga_max_size控制含 shared pool、buffer cache、redo log buffer、large pool、java poolPGA由pga_aggregate_target控制排序、哈希连接、PL/SQL 集合都在这里后台进程自身的堆栈、栈内存、OCI 层开销几十 MBOracle 客户端 DLL、代码映射段几十到一百多 MB经验上一个sga_target1500M、pga_aggregate_target500M的 11g 实例进程实际工作集在 2.2G 到 2.8G 之间浮动是正常的。你要是拿sga_target的数值去对标任务管理器永远会觉得超标了。2. 动手之前先把账算清楚别凭感觉调2.1 四条SQL把内存分布摸个底朝天调参最忌讳拍脑袋我一般先跑这几条语句把当前状态定格下来当基线改完再跑一遍做对比。第一条看总量show parameter sga_target; show parameter sga_max_size; show parameter pga_aggregate_target; show parameter memory_target; show parameter memory_max_target;memory_target如果非零说明开了 AMMAutomatic Memory Management这时候sga_target和pga_aggregate_target是被忽略的改它们没用这点后面会细说。第二条看 SGA 内部构成SELECT component, current_size/1024/1024 AS mb FROM v$sgainfo ORDER BY current_size DESC;第三条看动态组件实时占用SELECT component, current_size/1024/1024 AS mb FROM v$memory_dynamic_components WHERE current_size 0 ORDER BY current_size DESC;你会看到 buffer cache 往往占大头shared pool 次之。第四条看 PGA 实际用了多少SELECT name, value/1024/1024 AS mb FROM v$pgastat WHERE name IN (total PGA allocated,maximum PGA allocated,aggregate PGA target parameter);跑完这四条你心里就该有数了SGA 目标多少、实际用了多少、PGA 目标多少、实际峰值多少。2.2 Windows这一侧怎么看到真实占用SQL 侧看的是 Oracle 自己的账本操作系统侧还得单独看。任务管理器默认列表信息太少我习惯切到详细信息标签把提交大小Commit Size和工作集内存两列都调出来。工作集是实际占的物理内存提交大小是向系统申请的虚拟内存额度。这两个数差得越多说明有相当一部分内存被换到页面文件去了也就是俗称的被压到硬盘上了这种情况 Oracle 会明显变卡。命令行也能看开个 CMD 敲tasklist /svc /fi imagename eq oracle.exe这条会列出所有 oracle.exe 进程以及它们各自承载的服务名能帮你区分是实例服务还是别的。如果想看更细的内存映射情况用性能监视器加计数器Process\Working Set - Oracle*、Process\Virtual Bytes - Oracle*秒级采样跑上一两个小时看峰值。只看某一瞬间的数值没有意义Oracle 的 buffer cache 会随着查询量涨落得看一段时间内的最高点。顺带说一句如果你发现oracle.exe的 CPU 占用也异常高同时有个叫 antimalware service executable 的进程也在狂吃 CPU那多半是杀毒软件在实时扫描 Oracle 的数据文件.dbf。这种东西不解决内存问题但会把 IO 拖垮表现上跟内存不足很像容易误判。把 Oracle 的 ORADATA 目录、闪回区目录加进排除列表往往立竿见影。2.3 到底配多少才合理给你一张对照表内存配额不是越小越好。SGA 压得太狠buffer cache 装不下热数据每次查询都走物理 IOshared pool 压太小直接报 ORA-04031库都跑不起来。下面这张表是我在纯开发/学习机上反复验证过的经验值前提是这台机器只拿来学 Oracle、跑跑 SQL、做做课程设计不承载业务物理内存sga_targetsga_max_sizepga_aggregate_target进程预期占用8GB1024M1024M300M1.6-2.0G16GB1536M2048M512M2.2-2.8G32GB3072M4096M1024M4.2-5.0G64GB8192M12288M2048M10G 上下注意sga_target和sga_max_size的关系sga_target是当前目标可以在线调整sga_max_size是天花板只能在启动时确定在线改不了必须重启实例才生效。所以一般把sga_max_size设得略大于或等于sga_target留一点弹性空间。如果sga_target大于sga_max_size实例根本起不来报 ORA-00823 或 ORA-00824这个坑后面还会专门讲。3. 三套改法从最省事到最彻底3.1 只调SGA/PGA不关任何服务这是侵入性最小的做法适合机器内存还行、只是想稍微收一收的场景。先确认当前不是 AMM 模式也就是memory_target0。如果是 AMM得先关掉它转成 ASMMAutomatic Shared Memory Management否则改sga_target无效。具体操作用sqlplus / as sysdba登录后执行-- 先看当前是不是 AMM show parameter memory_target; -- 如果是 AMM先关掉需要重启 ALTER SYSTEM SET memory_target0 SCOPESPFILE; ALTER SYSTEM SET memory_max_target0 SCOPESPFILE; -- 同时给 sga/pga 设个明确值 ALTER SYSTEM SET sga_target1536M SCOPESPFILE; ALTER SYSTEM SET sga_max_size2048M SCOPESPFILE; ALTER SYSTEM SET pga_aggregate_target512M SCOPESPFILE;关掉 AMM 之后重启实例。重启完再想微调sga_target就能在线做了不用再重启ALTER SYSTEM SET sga_target1280M SCOPEBOTH;这里的SCOPE参数值得解释一下很多人搞混SCOPE 取值影响范围是否立即生效是否影响下次启动MEMORY只改内存是否SPFILE只改参数文件否是BOTH内存和参数文件都改是是sga_max_size只能写SPFILE因为它涉及内存分配结构在线改不了。这就是为什么调它必须重启。3.2 把用不上的服务关掉或改成手动这套是我最推崇的性价比最高纯赚内存而且几乎零风险。操作路径是Win R输入services.msc找到前面那张表里标可关的服务双击把启动类型从自动改成手动然后点停止。顺序上有个讲究先停实例服务相关的辅助服务最后再考虑实例本体。因为OracleDBConsoleorcl、ClrAgent这些服务是依赖实例服务启动的你直接把实例停了它们会跟着进入停止状态甚至报错。正确的顺序是停OracleDBConsoleorcl停OracleJobSchedulerORCL停OracleOraDb11g_home1ClrAgent停OracleMTSRecoveryService停OracleVssWriterORCL把这五个的启动类型全改成手动监听服务和实例服务保持自动启动不动。这样机器开机后只有实例和监听会跑起来内存占用能少 300-600MB具体取决于你原本开了几个。有两点要留意。第一OracleDBConsoleorcl停了之后https://localhost:1158/em那个网页控制台就打不开了如果你习惯用 EM 看性能报告得保留它或者需要时手动启动。第二ClrAgent停了之后数据库里那些用 .NET 写的存储过程会执行失败如果你没写过这类东西可以放心关。动手前先确认自己用不用这些功能别关完了才发现某个功能依赖它。还有一点有些服务在services.msc里改完启动类型重启后又变回自动了这通常是安装时注册表里写死了恢复策略。这种情况可以用管理员权限的 CMD 执行sc config 服务名 start demand来强制改注意等号后面有个空格。反过来想恢复自动就是start auto。3.3 从操作系统层面兜底防止内存被吃干数据库侧调完了还可以在系统侧加一道保险。Windows 10/11 有个内存压缩功能会在物理内存紧张时压缩不活跃的页面。这个功能对普通办公场景有用但对 Oracle 这种大块连续内存的进程来说压缩过程本身会消耗 CPU还可能让 Oracle 的响应变慢。如果你确认物理内存够用16G 以上可以考虑关掉内存压缩路径在启用或关闭 Windows 功能里或者用管理员 PowerShell 执行Disable-MMAgent -mc改完重启生效。反过来如果内存确实紧张那就别关让它帮你扛一扛。另一件事是页面文件虚拟内存。有人听信Oracle 要大页面文件的说法把页面文件设成固定 32G结果磁盘被吃掉一大块。开发机上让系统自动管理就够了除非你的物理内存真的捉襟见肘到需要大量换页那要考虑的其实是加内存条而不是调页面文件。页面文件只能缓解症状解决不了根本问题而且用多了 Oracle 会卡得让你怀疑人生。4. 拿一台16G开发机开刀全程实录4.1 调整前的基线记录我这台机器是 16G 内存的笔记本i7 处理器装的 Oracle 11g R2SID 是 ORCL。调整前先跑了一遍基线任务管理器里oracle.exe稳定在 3.1G 左右加上OracleDBConsoleorcl的 Java 进程 420M再加上监听、ClrAgent 等零碎光 Oracle 相关的服务就占了差不多 3.9G。开机后可用内存只剩 6G 出头再开个浏览器、IDE、几个 Docker 容器立马开始换页风扇狂转。SQL 侧查出来的参数是sga_target和sga_max_size都是 2Gpga_aggregate_target是 1Gmemory_target0已经是 ASMM 模式这是好事省了一步。v$sgainfo里 buffer cache 给了 1.1Gshared pool 给了 480M剩下的分给 large pool 和 java pool。4.2 一步步降下来第一步备份参数文件。这一步绝对不能省参数改错了还能拿回来-- 找到 spfile 位置 show parameter spfile; -- 用管理员权限把 spfileORCL.ora 复制一份改名备份Windows 上 spfile 通常在%ORACLE_HOME%\database\目录下名字类似SPFILEORCL.ORA。复制一份叫SPFILEORCL.ORA.bak放着出问题直接改回来。第二步算清楚目标值。物理内存 16G我要留至少 10G 给系统和开发工具Oracle 整体控制在 3G 以内。分配方案是 SGA 1536M PGA 512M 各种进程开销约 500M合计约 2.5G留有余量。于是定sga_max_size2048M、sga_target1536M、pga_aggregate_target512M。第三步执行调整。因为sga_max_size要改必须走 SPFILE 加重启ALTER SYSTEM SET sga_max_size2048M SCOPESPFILE; ALTER SYSTEM SET sga_target1536M SCOPESPFILE; ALTER SYSTEM SET pga_aggregate_target512M SCOPESPFILE;然后用shutdown immediate关实例再startup起来。这里提醒一句如果监听没起sqlplus / as sysdba走的是本地操作系统认证不受影响所以哪怕实例服务名称记错了用 sysdba 登录也是能进的。第四步关服务。重启实例成功后按 3.2 节的顺序把OracleDBConsoleorcl、OracleJobSchedulerORCL、OracleOraDb11g_home1ClrAgent、OracleMTSRecoveryService停掉并改为手动。监听和实例服务保持自动。4.3 验证效果和回滚准备重启机器等所有服务稳定后重新量一遍。oracle.exe的工作集降到 1.8G 左右额外的 Java 进程彻底消失整个 Oracle 相关占用降到 2.1G 上下比之前省了将近 1.8G。关键是可用内存从 6G 出头涨到 8G日常开发不再换页风扇安静了很多。验证 SQL 侧SELECT component, current_size/1024/1024 AS mb FROM v$memory_dynamic_components WHERE current_size 0 ORDER BY current_size DESC; SELECT * FROM v$sgainfo WHERE name LIKE %Granule% OR name IN (Buffer Cache Size,Shared Pool Size);如果发现 shared pool 明显偏小比如低于 200M跑复杂 SQL 或存储过程时容易报 ORA-04031那就回头把sga_target往上加 256M 再试。回滚很简单把备份的 spfile 覆盖回去重启实例再把那几个服务改回自动启动即可。我一般会把这套回滚步骤写在便签上贴在显示器边上改参数的时候心里踏实。5. 踩过的坑和排查速查表5.1 那些让你改完没反应的参数陷阱最常见的第一个坑改了sga_target重启后一查还是老值。原因十有八九是忘了加SCOPESPFILE只改了内存没写参数文件重启自然回到老值。反过来如果只写了SPFILE没重启当前内存里还是老值show parameter显示的是内存中的值会让你以为没改成。第二个坑在 AMM 模式下改sga_target无效。只要memory_target非零Oracle 就自己动态分配 SGA 和 PGA你设的sga_target只是个摆设。必须先按 3.1 节的步骤关掉 AMM重启后才生效。第三个坑sga_target设得比sga_max_size大实例直接起不来报 ORA-00823specified value of sga_target greater than sga_max_size或者 ORA-00824。这时候实例处于 NOMOUNT 状态用sqlplus / as sysdba能登进去把sga_target改小再启动就行。第四个坑把 SGA 压得太狠sga_target512M这种shared pool 被挤到只剩 100 多M一跑存储过程就 ORA-04031unable to allocate shared memory。经验底线是开发机sga_target不要低于 1024M11g 尤其吃 shared pool因为还有 java pool 和 streams pool 的开销。5.2 服务相关的疑难杂症关于服务问得最多的几个问题我都整理到下面这张表里了现象可能原因处理办法监听服务启动后立刻停止listener.ora 配置错误或端口被占用用lsnrctl status看报错检查 1521 端口是否被别的程序占改手动后重启又变自动注册表恢复策略写死管理员 CMD 执行sc config OracleServiceORCL start demand服务名找不到 Oral 开头的搜索词拼错实际是 ORCL按 SID 查OracleServiceSID才是实例服务实例服务起不来但没报错内存不足或 spfile 损坏查%ORACLE_HOME%\database\下的 alert 日志看最近几十行关掉 dbconsole 后 EM 打不开服务被停用需要时手动net start OracleDBConsoleorclOracle 卡到假死大量换页物理内存耗尽加大物理内存临时把 sga_target 调小别硬扛再说一个很多人会遇到的场景改了服务启动类型之后发现sqlplus连不上库提示 ORA-12541TNS: no listener或者 ORA-12514服务名未识别。前者是监听没起net start OracleOraDb11g_home1TNSListener即可后者是监听起来了但服务名对不上用lsnrctl status看监听到的服务名和你连接串里写的是否一致。这两个错误跟内存优化没关系但经常在折腾服务的过程中被带出来一慌就容易以为是改坏了。5.3 几条我踩出来的经验第一条改参数前一定备份 spfile这不是客套话。我有一次手抖把sga_max_size打成了sga_max_size2048少写 MOracle 按字节解析实例直接起不来最后靠备份文件恢复。这种错误不备份就得重装代价太大。第二条一次只改一个维度。要么这次只调内存参数要么这次只关服务别两件事一起上。同时动手的话出了问题分不清是哪个引起的。我一般先关服务跑两天稳定了再调参数。第三条区分学习机和生产机。上面所有的调优手段针对的都是个人开发、学习环境。生产库的 SGA 调优要看 AWR 报告、buffer cache 命中率、共享池的 library cache 命中率是一套完全不同的方法论不能照搬。你要是拿这套去动生产库出了事别怪我没提醒。第四条长期跑下来我自己的体会是16G 的机器给 Oracle 2G 到 2.5G 是最舒服的区间再往下压就开始影响使用体验再往上加收益不大。笔记本加内存条的钱其实比花几个小时反复调参数划算得多但如果你就是想把这台机器榨干那按上面这套流程走下来稳稳能省出 1.5G 到 2G够你再开一个 IDE 加一堆浏览器标签了。
返回列表