AIX分页空间是如何工作的。第一部分:为什么你的程序的内存占有有时变得臃肿

如果你从我以前的“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.


接着,测试程序。我需要他们中的三个:

  1. 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”到调页空间

  1. shmwrite: A ‘writer’ program to change SGA memory, to represent UPDATE operations

shmwrite:一个’writer’程序来改变SGA内存,代表UPDATE操作

  1. 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的内存快照是这样:

sga1

 

第二步:把“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”总体的内存图片看起来这样:

memory1

这里注意到一个微妙的东西:无分页空间作为未被分配的已被分配!

你可能想知道为什么它是微妙的,毕竟,显然的,仍然有大量的“实”空间可以提供…

但现在似乎显而易见的是,事实上,在AIX调页空间的行为有相当的近期的改善。直到系统需要调出页才分配分页空间, AIX 5.1 只有IBM引入延期分页空间分配政策。

在旧版本中,直到 PAGE OUT,AIX才会使用分页空间,然后默认后期分页空间分配政策,但无论如何会分配它。所以,AIX 5.1版本之前你看到的画面是这样的:

memory2-png

 

第三步:创建“外部”内存压力,迫使“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”内存的画面,现在看起来是这样的:

memory3

请注意,我们简单的内存估算公式仍然适用虚拟(整体请求)内存大小等于内存+分页空间。换句话说,内存或多或少从内存流向分页空间。

 

第四步:为了升级把“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


memory4

好,内存又一次“流”。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)块是真的被请求…

正如你所看到的那样,在读入操作的时候,分页空间不被释放,而很多内存页现在显示“双重分配”( “实存”和分页空间他们两个都“存在”),整体的内存图片是这样的:

memory5

 

这就是我们简单的公式崩塌的地方!

而这个问题自然就出现了——为什么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

*

沪ICP备14014813号-2

沪公网安备 31010802001379号