在学习Oracle内存结构的时候,发现一个问题:我的虚拟机Oracle环境参数文件中设置的sga_target=960M,但是在启动数据库时候,显示分配的Total System Global Area为1002127360 bytes(955.7M),那么问题就来了,为什么会不一致?相差的4.3M去干什么了?
学习后了解到SGA的分配与粒度(granule)相关,总结下知识。
1.什么是内存粒度
- 是连续的内存单元(unit of contiguous memory)。
- SGA分配的最小单位
- 按granule size的整数倍分配
- SGA组件,如Shared Pool、buffer cache、java池和其他池,在相同大小的粒度中进行分配和回收
- redo log buffer和Fixed Size不是按照granule分配
2.粒度的大小
- 粒度的大小是在实例启动时确定的,它取决于SGA_MAX_SIZE参数的大小
- 实例启动后,粒度大小不会改变,也就是说粒度大小在实例的生命周期内不变
- 数据库的粒度大小取决于平台和所分配的SGA总大小,下图显示的是linux下11gR2版本的粒度规则
- 如果你想要一个5MB的Java池,而你的粒度大小为4MB,Oracle实际上会为这个Java池分配8MB
- 查询granule size大小可以通过以下两个视图查询
select * from V$SGAINFO;
复制
select component,current_size/1024/1024 as MB,granule_size from V$SGA_DYNAMIC_COMPONENTS;
复制
- 粒度大小受内部隐含参数_ksmg_granule_size的控制
--查看隐含参数
col name for a30;
col value for a10;
select
x.ksppinm name,
y.ksppstvl value,
y.ksppstdf isdefault,
decode(bitand(y.ksppstvf,7),1,'MODIFIED',4,'SYSTEM_MOD','FALSE') ismod,
decode(bitand(y.ksppstvf,2),2,'TRUE','FALSE') isadj
from
sys.x$ksppi x,
sys.x$ksppcv y
where
x.inst_id = userenv('Instance') and
y.inst_id = userenv('Instance') and
x.indx = y.indx and x.ksppinm ='_ksmg_granule_size'
order by
translate(x.ksppinm, ' _', ' ')
/
复制
3.回到开头的问题
我的虚拟机Oracle环境参数文件中设置的sga_target=960M,但是在启动数据库时候,显示分配的Total System Global Area为1002127360 bytes(955.7M),那么问题就来了,为什么会不一致?相差的4.3M去干什么了?我们先来查看一下sga各个部分的情况
show sga
复制
Total System Global Area=Fixed Size+Variable Size+Database Buffers+Redo Buffers
单位bytes:1002127360=2259440+314574352+679477248+5816320
单位MB:955.7=2.15+300+648+5.55
- Fixed Size:SGA中固定组件(它在编译oracle 数据库本身时就固定于其中)的大小。它是固定大小的内存,用来容指向SGA的其它部分。SGA这一部分的大小是不能改变的。
- Database Buffers:就是buffer cache
- Redo Buffers:就是redo log buffer
- Variable Size:指分配的内存块大小可变。SGA的可变块,分为共享池、大池、JAVA池、游标区和其他结构。
再来看下V$SGA_DYNAMIC_COMPONENTS视图
select component,current_size/1024/1024 as MB,granule_size from V$SGA_DYNAMIC_COMPONENTS;
复制
可见各个池确实都是粒度(4MB)的倍数,大小也与show sga命令的能对应上
我们再来看两个对基表的查询,看得更清晰些
--1
col component format a32
select min(BASEADDR), max(BASEADDR), count(1) Granules, sum(a.gransize)/1048576 MB, a.GRANFLAGS, component, a.GRANSTATE
from x$ksmge a, x$kmgsct b
where a.grantype = b.grantype (+)
group by a.GRANFLAGS, component, a.GRANSTATE
order by 1,2;
复制
--2
select a.BASEADDR, a.gransize, a.GRANFLAGS, b.component, a.GRANSTATE
from x$ksmge a, x$kmgsct b
where a.grantype = b.grantype (+)
order by 1,2;
复制
太长只截取部分,总共237行,代表237个粒度,237x4=948,948+2.15+5.55=955.7,与上面查的都能匹配
4.参考
http://dbaparadise.com/2018/05/all-a-dba-needs-to-know-about-granules/
5.总结
1.通过上面学习,我判断SGA_MAX_TARGET与实际分配相差的4.3MB实际并没有分配,但是4.3MB已经大于一个粒度了,为什么不分配呢?有知道的大佬请留言告诉我,感谢
2.学习了管理内存粒度的知识
3.另外ipcs -m命令查看oracle启用分配了三个共享内存段,为什么不是分配一个呢,这块也需要再深究
4.补全Linux内存管理知识https://www.cnblogs.com/aspirs/p/13896571.html