之前也整理过一篇文章来说明Oracle Lock的,参考:
锁 死锁 阻塞 Latch 等待 详解
在这篇文章里,提到了System Locks,它包含:
(1)Latches
(2)Mutexes
(3)Internal Locks
一. 官方文档上关于Mutex 的说明如下
Mutexes
A mutual exclusion object (mutex) is a low-level mechanism that prevents an object in memory from aging out or from being corrupted when accessed by concurrent processes. A mutex is similar to a latch, but whereas a latch typically protects a group of objects, a mutex protects a single object.
Mutexes provide several benefits:
(1)A mutex can reduce the possibility of contention.
Because a latch protects multiple objects, it can become a bottleneck when processes attempt to access any of these objects concurrently. By serializing access to an individual object rather than a group, a mutex increases availability.
(2)A mutex consumes less memory than a latch.
(3)When in shared mode, a mutex permits concurrent reference by multiple sessions.
二. eygle 的blog上搜的信息
Mutex 的发音是 /mjuteks/ ,其含义为互斥(体),这个词是Mutual Exclude的缩写。
Mutex在计算机中是互斥也就是排他持有的一种方式,和信号量-Semaphore有可以对比之处。有人做过如下类比:
Mutex是一把钥匙,一个人拿了就可进入一个房间,出来的时候把钥匙交给队列的第一个。一般的用法是用于串行化对critical section代码的访问,保证这段代码不会被并行的运行。
Semaphore是一件可以容纳N人的房间,如果人不满就可以进去,如果人满了,就要等待有人出来。对于N=1的情况,称为binary semaphore。一般的用法是,用于限制对于某一资源的同时访问。
对于Binary semaphore与Mutex,这两者之间就存在了很多相似之处:
在有的系统中Binary semaphore与Mutex是没有差异的。
在有的系统上,主要的差异是mutex一定要由获得锁的进程来释放。而semaphore可以由其它进程释放(这时的semaphore实际就是个原子的变量,大家可以加或减),因此semaphore可以用于进程间同步。
Semaphore的同步功能是所有系统都支持的,而Mutex能否由其他进程释放则未定,因此建议mutex只用于保护critical section。而semaphore则用于保护某变量,或者同步。
三. google的其他信息
在Blog搜的信息如下:
http://www.hellodb.net/2010/06/oracle-mutex.html
Latch是Oracle用来在内存中做串行控制的机构,从10g R2开始,Oracle引入了一个新的技术Mutex。Mutex并不是Oracle的发明,而是系统提供的一个底层调用,Oracle只是利用它实现串行控制的功能,并替换部分Latch。
注意这里是部分替代:
Lateches can't be replaced by Mutex and Mutex are not replaced by latches. latches have more functionality than mutex. It is like enqueue is big ompared to lateches, lateches bigger than mutex. each and every low level serailaization device is seperate and have seperate roles.
Mutex是操作系统为了实现PV操作提供的原子功能,P/V两个操作都必须是原子的,才能保证并发不被打乱,与其相似的还有信号量Semaphore,这些都是操作系统原理上的东西了
Mutex中有两个变量:分别是Holider identifer和Reference count,Holider identifer记录持有mutex的SID,而Reference count是一个计数,记录了当前正在以share方式访问mutex的数量,每当session以share方式持有mutex时,计数会加1,而释放时会减1。如果Reference count大于零,则表示该内存结构正在被Oracle pin住。
我们看一段伪代码,演示mutex的申请过程:
Function Mutex_get(mutex_name)
{
if mutex.holder:=SID
case mode:
'exclusive':
if mutex.ref_count=0
return TRUE
else
mutex.holder.clear;
reture FALSE
end if
'share':
mutex.ref_count++
mutex.holder.clear
return TRUE
end case
else
reture FALSE
end if
}
Mutex是如何实现串行控制的,实际上它是利用了操作系统的一个原子操作CAS(compare-and-swap)实现的。
我们看到函数的开始处:mutex.holder:=SID,将SID赋值给mutex的Holider Identifer,这里就是一个原子的CAS操作,首先比较mutex.holder是否为空,如果不为空则赋值session的SID。CAS操作由OS来保证其原子性,在同一时刻这个操所是串行的。
如果这个赋值操作失败,整个申请过程失败。赋值成功后,如果是share方式,则mutex.ref_count加1,并清空mutex.holder,如果是exclusive方式,需要判断mutex.ref_count是否为零(是否被pin住),如果大于0,则失败,并清空mutex.holder,如果等于0,则成功,这时不清空mutex.holder,保持当前session对mutex的exclusive占用,直到释放为止。
Mutex相比latch带来了以下的好处:
1.更少的资源消耗,mutex与latch不同,它不是独立存在的,而是在每个内存结构中,并随着内存结构创建和释放,mutex同时也被创建和释放。mutex暂用的空间比latch小很多,创建和释放消耗更少的资源。
2.有效降低竞争,因为mutex是每个内存结构中的一部分,这样意味着mutex的数量可以有很多,而不同于latch,一个latch需要管理很多个内存结构,当你访问同一latch管理的不同内存结构时,也会发生竞争,而mutex则不会。
另外,因为latch的数量有限,很多时候latch本身的竞争会很厉害,之前,我们只能增加latch数量或者减少latch持有的时间,而现在,mutex是一个更好的选择。
3. 更快的pin,当block被访问时,它必须被pin在buffer cache中,当一个cursor执行时,它也必须被pin在library cache中,如果大量并发频繁执行同一个cursor,library cache pin会耗费大量的CPU资源。
而mutex使用reference count来解决并发访问的问题,只要它大于零,就表示它已经被pin在了内存中,不能被交换出去。 而且mutex.ref_count++这个操所是非常快的,只占用非常少的资源。
Mutex申请的过程和latch类似,同样需要spin和sleep,不同的是Oracle硬编码了mutex spin的次数为255次(Latch spin的次数默认为2000,由隐含参数_spin_count控制)。
latch sleep会随着等待次数的逐步增加,每次sleep的时间也会逐步增加。 mutex sleep则比较特别,它有三个选项,分别是yield CPU,sleep或者block other process,允许开发人员来决定采用哪种选项。
由于在某些RISC的操作系统中(HP-UNIX),由于系统不支持CAS操作,Oracle通过创建一个latch pool来模拟了CAS操作,被称为KGX latch,如果你发现系统中存在这种latch竞争,说明操作系统不支持CAS操作,可以通过_kks_use_mutex_pin关闭mutex。
mutex主要使用在library cache中,用来取代原来的library cache pin和library cache lock。
KGX mutexes are not OS mutexes, ORACLE KGX Mutex 同样是基于spinlock构建.
数据 1:
在10.2中,事情变得更加有趣,您可以使用KGX互斥锁来固定光标而无需获得库缓存引脚闩锁。互斥体是10.2中的新功能,它们以与共享闩锁类似的方式实现对对象的共享访问;特定互斥体的每次成功获取都会增加其值,并且释放将递减。当计数为零时,没有人拥有互斥体,将其置于独占模式是安全的。但是,据我所知,它们比kgl闩锁更细粒度,并提供了更好的等待机制。
因此,如果您的环境支持原子比较和交换操作(例如英特尔上的 CMPXCHG),则可能会在没有cursor_space_for_time设置的情况下获得超高执行率。否则,原子互斥体操作将使用新的 KGX 锁存器实现。
至少在我的笔记本电脑上,默认情况下不会启用此功能(从OracleWorld的一篇论文中,我记得它应该在10.2.0.2中成为默认值),但是到目前为止,如果您将_kks_use_mutex_pin = true设置为,则可以对其进行试验。
还有X$MUTEX_SLEEP和X$MUTEX_SLEEP_HISTORY固定表,如果您生成一些互斥体等待,它们可以显示一些有趣的信息。
数据 2:
互斥是短形式的互斥对象。互斥锁类似于锁存器,是一种低级序列化机制,用于控制对 SGA 中共享数据结构的访问。
2.1 需要序列化以避免对象出现:
(1) 在有人访问时解除分配
(2) 在有人修改时阅读
(3) 在有人修改时进行修改
(4)在有人阅读时修改
2.2 互斥体可以以不同的方式定义和使用,如以下示例所示:
(1)受互斥锁保护的每个结构都可以有自己的互斥体(例如,父游标有自己的互斥体,每个子游标都有自己的互斥体)
(2)每个结构可以由多个互斥体保护,每个互斥体保护结构的不同部分。
(3) 互斥体可以保护多个结构。
2.3 尽管互斥锁和闩锁都是序列化机制,但互斥锁具有锁存器所没有的某些功能:
(1)体积更小,速度更快
互斥体是锁存器的替代方案,因为它们更小,获取速度更快。与闩锁获取相比,互斥体 get 使用较少的指令。与闩锁相比,互斥锁占用的内存空间更少。
(2) 减少错误争用的可能性
闩锁通常保护多个对象。当闩锁保护一个或多个热物体时,当访问受该闩锁保护的任何物体时,闩锁本身可以成为序列化点。这可能是一个错误的争用点,其中争用的是保护机制(即闩锁),而不是您尝试访问的目标对象。与锁存器不同,使用互斥锁可以为受保护的每个结构创建互斥锁。这意味着错误争用的可能性要小得多,因为每个结构都可以由其自己的互斥体保护。
(3)更换闩锁和引脚
一个互斥体可以由多个会话同时引用,前提是所有会话都以 S(共享)模式引用互斥体。在 S 模式下引用互斥锁的会话总数称为引用计数(“引用计数”)。互斥锁的引用计数存储在互斥体本身中。互斥体也可以仅由一个会话在 X(eXclusive)模式下保持。
互斥体具有双重性质;它们可以充当序列化机制(例如,闩锁),也可以用作引脚(例如,防止对象老化)。例如,互斥锁的引用计数是库缓存引脚的替代品。在执行游标时,不是每个会话创建然后删除库缓存引脚,而是每个会话递增和递减 ref 计数(因此 ref 计数替换 n 个不同的引脚)。
注意: 锁存器和互斥锁是独立的机制,也就是说,进程可以同时持有闩锁和互斥锁。
2.4 互斥体操作比锁存器更快,争用更少,但互斥体操作仍然有与之关联的等待。两个 V$ 视图提供互斥锁睡眠的详细信息:
(1)V$MUTEX_SLEEP显示特定mutex_type/位置组合的睡眠和等待时间摘要。
SQL>从 v$mutex_sleep 中选择 *;
MUTEX_TYPE位置睡WAIT_TIME
-------------------------------- ---------------------------------------- ---------- ----------
Cursor Stat kksIterCursorStat [KKSSTALOC6] 103 163
Cursor Stat kksFindCursorStat [KKSSTALOC3] 23157 36724
Cursor Parent kksfbc [KKSCHLCREA] 1799 10170
Cursor Parent kkspsc0 [KKSPRTLOC27] 26 627
Cursor Parent kkspsc0 [KKSPRTLOC26] 122 2872
Cursor Parent kkshbbr [KKSPRTLOC15] 660 1779
Cursor Parent kksLoadChild [KKSPRTLOC4] 1181 6932
Cursor Parent kksfbc [KKSPRTLOC2] 9006 34053
Cursor Parent kksfbc [KKSPRTLOC1] 2831 144439
光标别克锁删除 [KKSCHLPIN6] 5021 1055990
Cursor Pin kkslce [KKSCHLPIN2] 265549 2792810468
Cursor Pin kksfbc [KKSCHLPIN1] 1203 5132409
Cursor Pin kksfbc [KKSCHLFSP2] 9279 56902065
(2)V$MUTEX_SLEEP_HISTORY显示按时间为特定mutex_type/位置组合而睡觉的会话,而该会话由特定的举行会话进行。
2.5 互斥等待事件分为两类:
(1)cursor:mutex 表示互斥体等待父级游标操作和统计块操作。
(2)cursor:pin 事件等待光标引脚操作,其中互斥体已替换锁存器:库缓存引脚。
2.6 互斥等待事件有两种类型
(1)应很少见的短期事件。当一个进程尝试更新互斥体而另一个进程正在更改互斥体时,就会发生这种情况。等待过程将旋转等待互斥体可用。例如,当另一个进程更新共享游标的引用计数(pin)时,cursor:pin S 会递增。
(2) 当一个进程必须等待其他进程完成其操作时,就会发生持续时间较长的事件。例如,当一个进程想要独占访问权限,但该互斥体被另一个进程独占或共享时,cursor:mutex X 会递增。
2.7 受互斥保护的操作:
互斥体是可以保护关键操作的另一种保护机制。在 Oracle 数据库 V. 10.2.0.2 及更高版本中,V$SQLSTATS 视图中的 SELECT 受互斥锁保护。使用受互斥锁保护的操作明显快于锁存操作。子游标列表受互斥锁保护。
小结:
这些资料先是看了一遍,然后整理了一篇。 感觉还是有点没吃透。 Oracle 内存这块的东西还需要深入研究。 先这样吧。 以后有新理解的时候在修改。