如果你从我以前的“AIX内存”的帖子(进程内存,SGA内存)回忆AIX内存的传奇故事,其中一个点就是这一进程在任何给定时刻的寿命(或共享内存段)在每个分配的内存页可以驻留在这两个地方之一:
- 无论是页面位于物理RAM
- 或页面位于分页空间
很明显在内存里更好。如果我是一个内存页我会想在哪里,在分页空间?没有这么多,如果我不够热门并且AIX需要记忆其他东西,我当然可以在那里被强迫换出。
正如你所看到的,在逻辑上,“页面位置”是一个独特的非此即彼/或处理——无论是页面在内存或它是在调页空间——它永远是“在两者之间”。在某种程度上,虚拟内存“流”之间的物理内存和调页空间,正因为如此,下面的近似公式应该成立:
Virtual (memory requested by the process) = InMemory + InPagingSpace
虚拟(内存工艺要求)=内存+调页空间
这个公式是很有逻辑性的也很好理解…甚至可以适用在完美世界(不需要内存优化)。
不幸的是在我们的世界我们可能会在内存分配时遇到麻烦,像这样:
---------- -- ---------- ---------- ---------- ---------- Vsid Pg InMem Pin Paging Virtual ---------- -- ---------- ---------- ---------- ---------- 3d0778 s 0.00 0.00 0.00 0.00 ... 37876d s 255.28 0.00 221.55 255.94 36076e s 255.31 0.00 219.55 255.94 358769 s 255.33 0.00 220.97 255.94 ---------- -- ---------- ---------- ---------- ---------- TOTAL: 7796.02 0.00 6550.62 7914.35 Requested SGA: 8192.02 Segments: 33
这里,我们的计算显然有一个问题:7,796 + 6,550 = 14,346比虚存大小7,914大了好多。
那么,发生了什么?内存哪里去了?我们真正利用了多少?
AIX分页空间是如何工作的
发生了什么的答案又给了我们一个AIX的技巧。
简短来说:
在AIX,分页空间在页被读回内存时可能不会被释放
在这篇文章中,我要创建将分配AIX共享内存段(ORACLE模仿SGA)的几个小C程序,为了展现AIX分页空间详细如何工作的,但同样的逻辑应该适用于任何AIX计算内存,定期地管理,并且是符合页输出的(*)。所以,让我们开始吧,好吗?
(*)这有一个不规范管理AIX内存的例子
第零步.设置环境…
为了看到分页空间的行为,我们显然需要使用它。这意味着,我们不得不创建系统条件,这会鼓励分页…或者,换句话说,我们的程序应该(极大)要求比现有系统更多的内存
首先,以便不让我们的工作太难了,让我们人为地限制可用内存量为3千兆
AIX> rmss -c 3000 Simulated memory size changed to 3000 Mb.
接着,测试程序。我需要他们中的三个:
- shmalloc: A program to allocate shared memory. We will use it to mimic ORACLE SGA as well as (in a separate instance) to create “external” workload and push “SGA” into paging space
shmalloc:一个程序来分配共享内存。我们将用它来模拟Oracle SGA以及(在一个单独的实例)创建“外部”的工作量,推动“SGA”到调页空间
- shmwrite: A ‘writer’ program to change SGA memory, to represent UPDATE operations
shmwrite:一个’writer’程序来改变SGA内存,代表UPDATE操作
- shmread: A ‘reader’ program to read SGA memory and emulate SELECT operations
shmread:一个’reader’程序读取SGA内存并仿效SELECT操作
好,现在提前准备已经做好,让我们开始测试。
第一步:启动“SGA” …
Here we are "Creating ORACLE SGA" 1.2 Gb in size AIX>shmalloc 1200000000 1 Shared memory segment: 98566147 (1200000000) has been CREATED Shared memory segment: 98566147 has been ATTACHED. Shared memory segment: 98566147 has been POPULATED. Initial allocated size: 180000000 bytes. Now sleeping for 6000 seconds ... # Let's double check that shared memory segment has really been created AIX> ipcs -bm | grep 98566147 m 98566147 0x01035077 --rw------- oracle dba 1200000000 # And finally let's see where "SGA" memory is AIX> ps -fu oracle | grep shmalloc oracle 192654 577598 0 09:48:25 pts/0 0:00 shmalloc 1200000000 1 AIX>svmon -P 192654 | grep shmat Vsid Esid Type Description PSize Inuse Pin Pgsp Virtual 6878f 70000000 work default shmat/mmap s 43946 0 0 43946 48a0b 70000003 work default shmat/mmap s 0 0 0 0 7898d 70000001 work default shmat/mmap s 0 0 0 0 689ef 70000004 work default shmat/mmap s 0 0 0 0 68a0f 70000002 work default shmat/mmap s 0 0 0 0
这是我们的”SGA”第一快照后马上启动。注意到现在它使用的物理内存为180 MB,而不是被要求的1.2 GB。你可能还记得,这是因为,AIX直到它被实际使用(而此刻,我们只使用180 MB)才分配内存。
Current SGA memory snapshot looks like this:
现在SGA的内存快照是这样:
第二步:把“SGA”装入内存…所有的“SGA”内存都在内存里面
让我们把更多的“SGA”装入内存…为此我们要用shmwrite程序(但用真正的ORACLE实例,您可以使用,即全表扫描的大表……至少,如果你仍然在Oracle 10g中)
AIX> shmwrite 1200000000 1 A SHMGET successful for: 98566147 SHMAT successful for: 98566147 Memory space has been WRITTEN: 1200000000 bytes, symbol: A
在升级“SGA”内存之后,它完全被分配。而且,作为仍然是镇上唯一的游戏的“SGA”,它完全适合于可用的物理RAM:
AIX> svmon -P 192654 | grep shmat 6878f 70000000 work default shmat/mmap s 65536 0 0 65536 68a0f 70000002 work default shmat/mmap s 65536 0 0 65536 7898d 70000001 work default shmat/mmap s 65536 0 0 65536 48a0b 70000003 work default shmat/mmap s 65536 0 0 65536 689ef 70000004 work default shmat/mmap s 30825 0 0 30825
“SGA”总体的内存图片看起来这样:
这里注意到一个微妙的东西:无分页空间作为未被分配的已被分配!
你可能想知道为什么它是微妙的,毕竟,显然的,仍然有大量的“实”空间可以提供…
但现在似乎显而易见的是,事实上,在AIX调页空间的行为有相当的近期的改善。直到系统需要调出页才分配分页空间, AIX 5.1 只有IBM引入延期分页空间分配政策。
在旧版本中,直到 PAGE OUT,AIX才会使用分页空间,然后默认后期分页空间分配政策,但无论如何会分配它。所以,AIX 5.1版本之前你看到的画面是这样的:
第三步:创建“外部”内存压力,迫使“SGA”页调出页
好,继续…现在,让我们模拟一些工作量并创建系统一个巨大的内存压力。这将有希望让AIX调出一些“SGA”的页面…
为了模拟“外部内存压力”,让我们通过其他进程请求一些
首先,我们现在有多少内存?
AIX>svmon -G size inuse free pin virtual stolen memory 798420 522077 276343 179670 590293 1167660
会有:能使用的RAM有276343 * 4k 到 1.3 Gb。可以确定的是,我们现在请求2Gb。有希望的是,这会强迫我们的“SGA”有一部分到分页空间去。
AIX> shmalloc 2000000000 2 Shared memory segment: 368050180 (2000000000) has been CREATED Shared memory segment: 368050180 has been ATTACHED. Shared memory segment: 368050180 has been POPULATED. Initial allocated size: 300000000 bytes. Now sleeping for 6000 seconds ... AIX> shmwrite 2000000000 2 B SHMGET successful for: 368050180 SHMAT successful for: 368050180 Memory space has been WRITTEN: 2000000000 bytes, symbol: B
由于我们的“SGA”被闲置,并因此代表旧的工作量,它必须让路……它的确这么做了:
AIX svmon -P 192654 | grep shmat 68a0f 70000002 work default shmat/mmap s 60362 0 5174 65536 7898d 70000001 work default shmat/mmap s 53229 0 12307 65536 6878f 70000000 work default shmat/mmap s 0 0 65536 65536 48a0b 70000003 work default shmat/mmap s 0 0 65536 65536 689ef 70000004 work default shmat/mmap s 0 0 30825 30825
在“SGA”内存中重要的一部分被转移到分页空间,而且整体“SGA”内存的画面,现在看起来是这样的:
请注意,我们简单的内存估算公式仍然适用虚拟(整体请求)内存大小等于内存+分页空间。换句话说,内存或多或少从内存流向分页空间。
第四步:为了升级把“SGA”从内存中带回来
我们已经看到了内存和分页空间在调出页如何操作的…现在,让我们看看它们如何在调入页操作的…
为了做这个,我们杀死“外面的工作量”(从而使系统再次有大量的可用内存),并通过请求另一个更新的页面请求“SGA”返回RAM:
# Killing "external memory workload" AIX> ipcrm -m 368050180 # Let's check the status of our "SGA" BEFORE update AIX> svmon -P 192654 | grep shmat svmon -P 409662 | grep shmat 68a0f 70000002 work default shmat/mmap s 60362 0 5174 65536 7898d 70000001 work default shmat/mmap s 53229 0 12307 65536 6878f 70000000 work default shmat/mmap s 0 0 65536 65536 48a0b 70000003 work default shmat/mmap s 0 0 65536 65536 689ef 70000004 work default shmat/mmap s 0 0 30825 30825 # Now, let's update some of the "SGA" # (this will recall "SGA" memory pages back in memory) ... AIX> shmwrite 480000000 1 C SHMGET successful for: 98566147 SHMAT successful for: 98566147 Memory space has been WRITTEN: 480000000 bytes, symbol: C # And now, let's check "SGA" state AFTER update AIX> svmon -P 192654 | grep shmat 7898d 70000001 work default shmat/mmap s 65536 0 0 65536 6878f 70000000 work default shmat/mmap s 65536 0 0 65536 68a0f 70000002 work default shmat/mmap s 60362 0 5174 65536 48a0b 70000003 work default shmat/mmap s 0 0 65536 65536 689ef 70000004 work default shmat/mmap s 0 0 30825 30825
好,内存又一次“流”。100%的我们RAM,仍然通过我们简单的内存分配公式解释,像: 60362+5174 = 65536.我们“SGA”内存仍然是粗略的一个零和游戏…
它看起来像一旦相关的页面更新操作期间读入内存,分页空间就被释放…
这种分页空间的行为,顺便说一句,其实是成为仅适用于AIX 5.3的另一大特色。分页空间释放被垃圾回收机制,默认情况下,仅在调入页操作过程中控制…
第五步:为了读入把“SGA”从内存中取出来
我们已经看到,当为了更新内存页被带回内存时,分页空间被释放…如果我们简单地读取,会有相同的真的保留吗?让我们来看看…
首先,我们重复 “SGA”溢出再分页空间的步骤:
AIX> shmalloc 2000000000 2 Shared memory segment: 371195908 (2000000000) has been CREATED Shared memory segment: 371195908 has been ATTACHED. Shared memory segment: 371195908 has been POPULATED. Initial allocated size: 300000000 bytes. Now sleeping for 6000 seconds ... AIX> shmwrite 2000000000 2 B SHMGET successful for: 371195908 SHMAT successful for: 371195908 Memory space has been WRITTEN: 2000000000 bytes, symbol: B
现在,让我们卸掉“外部负载”,读入“SGA”记忆…
# Kill "external memory workload" AIX> ipcrm -m 371195908 # Checking status of "SGA" BEFORE read AIX> svmon -P 192654 | grep shmat 6878f 70000000 work default shmat/mmap s 65536 0 0 65536 7898d 70000001 work default shmat/mmap s 28243 0 37293 65536 68a0f 70000002 work default shmat/mmap s 11325 0 54211 65536 48a0b 70000003 work default shmat/mmap s 0 0 65536 65536 689ef 70000004 work default shmat/mmap s 0 0 30825 30825 # Let's read some memory AIX> shmread 480000000 1 SHMGET successful for: 98566147 SHMAT successful for: 98566147 Memory space has been READ: 480000000 bytes, symbol: C # And now let's check "SGA" status AFTER read AIX>svmon -P 192654 | grep shmat 48a0b 70000003 work default shmat/mmap s 65536 0 65536 65536 7898d 70000001 work default shmat/mmap s 65536 0 37293 65536 6878f 70000000 work default shmat/mmap s 65536 0 0 65536 68a0f 70000002 work default shmat/mmap s 65536 0 54211 65536 689ef 70000004 work default shmat/mmap s 30825 0 30825 30825
哇,这是奇怪!2号线路为例:65536+37293=102829…然而,只有65536(4K)块是真的被请求…
正如你所看到的那样,在读入操作的时候,分页空间不被释放,而很多内存页现在显示“双重分配”( “实存”和分页空间他们两个都“存在”),整体的内存图片是这样的:
这就是我们简单的公式崩塌的地方!
而这个问题自然就出现了——为什么AIX上没有读入的释放分页空间?如果我们的内存在RAM里是“真正”的,“剩”的分页空间的副本有什么好处?
嗯,一旦你意识到这个问题,那就可以非常简单的计算出来了:
- 一旦很可能再次这样做,内存已经调出页…
- 读取调入页之后,剩下的“分页空间”页拷贝,保持相同即“内存”的双胞胎
因此,在一个调出页之后的可能性上(假设内存之间并没有改变),AIX可以简单地放弃内存页面,将不再需要将它的内容复制回分页空间……这确实代表了AIX一些严重的积累……
因此,从本质上讲,通过保持“相关”内存拷贝在分页空间AIX,AIX将自己定位为潜在的(可能)跳过一些严肃地未来的工作,和多一点的磁盘空间,这些被用来获得增益效率且只是花费一个很小的代价。
第六步:为了读取和之后的更新把“SGA”从内存中取出来
你可能想知道——如果原来内存页被调入页来“读”,但后来再改会发生什么?难道他们打算从分页空间变化的时间被“释放”?
让我们来看看…
# Let's read ALL the "SGA" memory to be 100 % sure AIX> shmread 1200000000 1 SHMGET successful for: 98566147 SHMAT successful for: 98566147 Memory space has been READ: 1200000000 bytes, symbol: C AIX> Check SGA status BEFORE memory update AIX> svmon -P 192654 | grep shmat 48a0b 70000003 work default shmat/mmap s 65536 0 65536 65536 7898d 70000001 work default shmat/mmap s 65536 0 37293 65536 6878f 70000000 work default shmat/mmap s 65536 0 0 65536 68a0f 70000002 work default shmat/mmap s 65536 0 54211 65536 689ef 70000004 work default shmat/mmap s 30825 0 30825 30825 # Update ALL the "SGA" memory AIX> shmwrite 1200000000 1 R SHMGET successful for: 98566147 SHMAT successful for: 98566147 Memory space has been WRITTEN: 1200000000 bytes, symbol: R # And now, let's check "SGA" state AFTER AIX> svmon -P 716870 | grep shmat 48a0b 70000003 work default shmat/mmap s 65536 0 65536 65536 68a0f 70000002 work default shmat/mmap s 65536 0 54211 65536 7898d 70000001 work default shmat/mmap s 65536 0 37293 65536 6878f 70000000 work default shmat/mmap s 65536 0 0 65536 689ef 70000004 work default shmat/mmap s 30825 0 30825 30825
看起来答案是:不行。即使内存真的改变了,也不再符合其“分页空间”副本了,“SGA”内存仍然是双分配。
这是因为默认的垃圾收集过程只在操作页面中进行(至少,直到6.1 ML5),如果没有调入页(记住,在读取后,所有的“SGA”的页面已经“进入内存”),那么就不能释放调页空间。
这里的底线是,用我们简单的内存估算公式来计算AIX分页空间可能不再产生正确的结果。
那么,有没有什么方法来修补?
答案肯定是有,并且奇怪的是,你得到的公式(以及结果)将取决于你问的具体问题。
比方说,你想知道你的程序的内存中有多少是“真正”的分页空间?(这是一个性能优化问题)。
这里的关键点是,在当存储器页双重分配的时间时,主页复制是ALWAYSin存储器。因此,svmon的“INUSE”字段返回“真”的数据,而“pgsp”值是人为的“臃肿”(重复计算页面空间,在内存中是“真”)。
因此,“实”分页空间公式将会是:
InPagingSpace (“real”) = Virtual – InMemory
分页空间(“实”)=虚-内存
或者,你可能会想知道,有多少分页空间正在被你的程序使用? (这是调页空间大小的问题)。
在这种情况下,svmon的“pgsp”的值是不会再被“臃肿”的——是的,页面在此被算了两次,但他们仍然物理分配。
因此,资源使用的公式看起来像我们原来的简单的内存分配公式:
Resources Used = InMemory + InPagingSpace
资源利用=内存+分页空间
只是“是干什么用的”未必等于“要求是什么”(虚拟)了…
Comment