[20250202]21c library cache mutex的深入探究5.txt

[20250202]21c library cache mutex的深入探究5.txt

--//前面的学习已经了解21c library cache mutex chunk分布的特点,再次总结如下:
--//1个chunk 有256个mutex地址,占用12304,每个前面有16字节开头,许多chunk在内存分布上紧挨的。共计512个chunk。
--//在1个chunk内muetx每个偏移48字节.
--//我的测试被分成3个大片:注:我在另外一台生产系统看到分成2个大片。
--//通过fchaz脚本查询对应的KSMCHPAR,没有信息输出。

--//问题来了,如果第一次执行一条sql语句,知道bucket桶号,oracle如何定位到相应mutex地址。
--//在11g下开始学习以为整个在一个chunk里面,这样知道基地址加上偏移量就可以知道buckect桶号就可以定位mutex地址。
--//实际上的情况在21c分布在存在于512个chunk中,前面的测试许多chunk在内存分布上紧挨的,分成3个大片。显然不能通过上面简单
--//计算定位mutex地址。

--//在11g下通过查询x$ksmmem,获得相应值,而21c下遇到问题,展开下面的分析。

1.环境:
SYS@book> @ver2
==============================
PORT_STRING                   : x86_64/Linux 2.4.xx
VERSION                       : 21.0.0.0.0
BANNER                        : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
BANNER_FULL                   : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
BANNER_LEGACY                 : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
CON_ID                        : 0
PL/SQL procedure successfully completed.

2.简单介绍:
SYS@book> select count(*),KSMCHPAR from x$ksmsp where KSMCHCOM='KGLSG'  and KSMCHSIZ=12304 group by KSMCHPAR;
  COUNT(*) KSMCHPAR
---------- ----------------
        31 000000006CC04000
       339 000000006C804000
       142 000000006C434000
--//Sum = 512。
--//前面的测试在一个chunk内每个mutex地址相邻相差48字节,48*256+16 = 12304,也就是1个chunk保存256个mutex地址。

SYS@book> @ fchaz 000000006CC04000
no rows selected

SYS@book> @ fchaz 000000006C804000
no rows selected

SYS@book> @ fchaz 000000006C434000
no rows selected
--//堆描述符并没有占用空间,我个人认为启动时存在的,建立library cache mutex的chunk后删除了。

SYS@book> select * from (select * from x$ksmmem order by addr desc) where rownum=1;
ADDR                   INDX    INST_ID     CON_ID KSMMMVAL
---------------- ---------- ---------- ---------- ----------------
000000006093DFA0    1211380          1          1 00
--//使用x$ksmmem查询的最大地址是000000006093DFA0.而实际上sga占用内存分布如下:

$ pmap -x $(pgrep pmon) | egrep  -i "sysv|^Address"
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000060000000   10240       0       0 rw-s- SYSV00000000 (deleted)
~~~~~~~~~~~~~~~~
0000000060c00000  770048       0       0 rw-s- SYSV00000000 (deleted)
000000008fc00000    8192       0       0 rw-s- SYSV00000000 (deleted)
--//使用x$ksmmem仅仅查询到下划线的内存区域,不能再使用它查询整个sga。
--//不过在11g的测试中已经知道其内存地址就在bucket =0 的mutex地址前面的。
--//注:11g 下在同1个chunk,21c情况不是。

3.分析:
--//转储library_cache:
SCOTT@book01p> select /*+ 9 */ count(*) from dept where deptno = 93834;

  COUNT(*)
----------
         0

SCOTT@book01p> @ hash

HASH_VALUE SQL_ID        CHILD_NUMBER KGL_BUCKET PLAN_HASH_VALUE HASH_HEX   SQL_EXEC_START      SQL_EXEC_ID
---------- ------------- ------------ ---------- --------------- ---------- ------------------- -----------
3403546624 as3g00v5dw000            0          0      2236899148  cade0000  2025-02-02 15:19:04    16777221

SYS@book> oradebug setmypid
Statement processed.
SYS@book> oradebug dump library_cache 4
Statement processed.

$ grep "^Bucket:" /u01/app/oracle/diag/rdbms/book/book/trace/book_ora_10770.trc | head -4
Bucket: #=0 Mutex=0x6cfa1400(1125281431552, 9, 0, 6)
Bucket: #=5 Mutex=0x6cfa14f0(1125281431552, 4, 0, 6)
Bucket: #=17 Mutex=0x6cfa1730(1125281431552, 8, 0, 6)
Bucket: #=39 Mutex=0x6cfa1b50(1125281431552, 4, 0, 6)
--//Bucket: #=0 Mutex=0x6cfa1400
--//0x6cfa1400-0x10 = 0x6cfa13f0

SYS@book> @ fchaz 0x6cfa1400
LOC KSMCHPTR           KSMCHIDX   KSMCHDUR KSMCHCOM           KSMCHSIZ KSMCHCLS   KSMCHTYP KSMCHPAR         KSMCHPTR_BEGIN   KSMCHPTR_END+1
--- ---------------- ---------- ---------- ---------------- ---------- -------- ---------- ---------------- ---------------- -----------------
SGA 000000006CFA13E0          1          1 KGLSG                 12304 perm              0 000000006CC04000 000000006CFA13E0 000000006CFA43F0

--//0x000000006CFA13E0-0x1 = 0x6cfa13df

SYS@book> @ fchaz 000000006CFA13df
LOC KSMCHPTR           KSMCHIDX   KSMCHDUR KSMCHCOM           KSMCHSIZ KSMCHCLS   KSMCHTYP KSMCHPAR         KSMCHPTR_BEGIN   KSMCHPTR_END+1
--- ---------------- ---------- ---------- ---------------- ---------- -------- ---------- ---------------- ---------------- -----------------
SGA 000000006CFA03C0          1          1 KGLSG                  4128 perm              0 000000006CC04000 000000006CFA03C0 000000006CFA13E0

--//在Bucket: #=0前面的chunk大小KSMCHSIZ=4128,KSMCHCOM=KGLSG(类型与后面的chunk一样)。
--//如果每个地址占用8个字节,共计512个,4128-512*8 = 32。基本猜测正确,验证看看。

SYS@book> @ opeek 000000006CFA03C0 64 1
New tracefile_identifier = /u01/app/oracle/diag/rdbms/book/book/trace/book_ora_3412_0005.trc
[06CFA03C0, 06CFA0400) = 00001021 00B38F00 17ADF8D0 00000000 6CFA03E0 00000000 000016E8 00020000 6CFA13F0 00000000 6CFA4400 00000000 6CFA7410 00000000 ...
                                                                                                 ~~~~~~~~          ~~~~~~~~~         ~~~~~~~~
--//0x00001021 = 4129 = 4128+1 ,看来chunk的开头前4字节保存的是chunk大小+1.
--//注意看下划线值(前面占用32字节),正好等于0x6cfa1400-0x10 = 0x6cfa13f0。
--//0x6CFA4400-0x6CFA13F0 = 12304
--//0x6CFA7410-0x6CFA4400 = 12304
--//前后相减正好等于12304.

--//实际上很简单在一个chunk里面记录了一张表或者讲一个数组,记录数量为2^_kgl_bucket_count,每个占8字节(我的OS 64位系统),相
--//当于N*256的mutex地址(N=0到511),假设知道基地址A后,如果知道bucket值.使用bucket/256 取整就可以定位 该地址B 保存在
--//A + trunc(bucket/256)*8的位置,再通过bucket%256 * 40 + B , 该位置就保存了该bucket的library cache mutex的地址。

4.验证分成3个大片:

SYS@book> @ opeek 000000006CFA03C0 4128 1
New tracefile_identifier = /u01/app/oracle/diag/rdbms/book/book/trace/book_ora_3412_0007.trc
[06CFA03C0, 06CFA13E0) = 00001021 00B38F00 17ADF8D0 00000000 6CFA03E0 00000000 0000188E 00020000 6CFA13F0 00000000 6CFA4400 00000000 6CFA7410 00000000 ...

$ sed -n "/^06CFA03E0/,/^06CFA13D0/p" /u01/app/oracle/diag/rdbms/book/book/trace/book_ora_3412_0007.trc | awk '{print $2"\n"$4}' > d2.txt
$ head -4 d2.txt
6CFA13F0
6CFA4400
6CFA7410
6CFAA420

$ wc d2.txt
 512  512 4608 d2.txt

$ awk 'NR==1{a=$1} NR>1{ print $1,a,strtonum("0x"$1)-strtonum("0x"a);a=$1}'  d2.txt | head -10
6CFA4400 6CFA13F0 12304
6CFA7410 6CFA4400 12304
6CFAA420 6CFA7410 12304
6CFAD430 6CFAA420 12304
6CFB0440 6CFAD430 12304
6CFB3450 6CFB0440 12304
6CFB6460 6CFB3450 12304
6CFB9470 6CFB6460 12304
6CFBC480 6CFB9470 12304
6CFBF490 6CFBC480 12304

$ awk 'NR==1{a=$1} NR>1{ print $1,a,strtonum("0x"$1)-strtonum("0x"a);a=$1}'  d2.txt | awk '{print $3}'| uniq -c
     30 12304
      1 -8353184
    338 12304
      1 -8156448
    141 12304
--//与前面的select count(*),KSMCHPAR from x$ksmsp where KSMCHCOM='KGLSG'  and KSMCHSIZ=12304 group by KSMCHPAR;输出可以对上。

5.顺便找一条实际的sql语句测试看看。

SCOTT@book01p> select * from dept where deptno = 40 ;
    DEPTNO DNAME                          LOC
---------- ------------------------------ -------------
        40 OPERATIONS                     BOSTON

SCOTT@book01p> @ hash
HASH_VALUE SQL_ID        CHILD_NUMBER KGL_BUCKET PLAN_HASH_VALUE HASH_HEX   SQL_EXEC_START      SQL_EXEC_ID
---------- ------------- ------------ ---------- --------------- ---------- ------------------- -----------
  61084640 2k056r41u84z0            0       5088      2852011669   3a413e0  2025-02-02 16:22:05    16777216

--//KGL_BUCKET=5088,计算就是使用HASH_VALUE % (2^_kgl_bucket_count * 256),缺省_kgl_bucket_count=9.61084640%2^17 = 5088
--//5088/256 = 19.875,取整就是19,取模 5088%256 = 224 ,224 = 0xe0

$ sed -n "20,20p" d2.txt
6CFDA520
--//注意从0开始计数,相当于取20行的记录。
--///6CFDA520+0x30*0xe0  = 0x6cfdcf20

SYS@book> @ opeek 0x6cfdcf20 48 0
[06CFDCF20, 06CFDCF50) = 671C92D8 00000000 671C92D8 00000000 00000000 00000000 0000000B 00000000 000013E0 00000000 64CEEB50 00000000

SYS@book> @ sharepool/shp4z 2k056r41u84z0 -1 ''
HANDLE_TYPE            KGLHDADR         KGLHDPAR         C40                                        KGLHDLMD   KGLHDPMD   KGLHDIVC KGLOBHD0         KGLOBHD6           KGLOBHS0   KGLOBHS6   KGLOBT16   N0_6_16        N20   KGLNAHSH KGLOBT03        KGLOBT09
---------------------- ---------------- ---------------- ---------------------------------------- ---------- ---------- ---------- ---------------- ---------------- ---------- ---------- ---------- --------- ---------- ---------- ------------- ----------
parent handle address  00000000671C92D8 00000000671C92D8 select * from dept where deptno = 40              1          0          0 00000000679A7B48 00                     4064          0          0      4064       4064   61084640 2k056r41u84z0      65535

--//parent handle address=00000000671C92D8,与opeek的输出前面16字节 能够对上。
--//0x000013E0  = 5088 ,正好等于bucket桶号。

6.小结:
--//实际上很简单在一个chunk里面记录了一张表或者讲一个数组,记录数量为2^_kgl_bucket_count,每个占8字节(我的OS 64位系统),相
--//当于N*256的mutex地址(N=0到511),假设知道基地址A后,如果知道bucket值.使用bucket/256 取整就可以定位 该地址B 保存在
--//A + trunc(bucket/256)*8的位置,再通过bucket%256 * 40 + B , 该位置就保存了该bucket的library cache mutex的地址。

posted @   lfree  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
历史上的今天:
2024-02-19 [20240219]建立完善sql_idx.sh脚本.txt
2019-02-19 [20190219]那个更快(11g).txt
点击右上角即可分享
微信分享提示