32bit oracle由於位元限制,使得oracle進程只能訪問4g(2的32次方)以下的虛擬記憶體地址,在很多時候這是一個很讓人頭疼的問題,因為空白著許多記憶體而不能使用,而預設情況下SGA不能超過1.7g。比如我們的linux下有8g記憶體,卻有部分空著不能用干著急。這個時候我們就要考慮怎樣擴充oracle的SGA。那麼首先,如何識別32bit的oracle呢?我們可以通過如下查詢得到
sys@OCN> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
PL/SQL Release 9.2.0.4.0 - Production
CORE 9.2.0.3.0 Production
TNS for Linux: Version 9.2.0.4.0 - Production
NLSRTL Version 9.2.0.4.0 - Production
如果是64bit oracle,在查詢結果中一定會顯示 64bit 字樣,沒有出現,則一定是32bit oracle .當然,在os上通過file oracle 也能看到
[oracle@ocn2 bin]$ cd $ORACLE_HOME/bin
[oracle@ocn2 bin]$ file oracle
oracle: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked (uses shared libs), not stripped
[oracle@ocn2 bin]$
在某些os上,比如AIX上,64bit oracle 會正常顯示資訊,32bit則不正常顯示。
在確認了32bit oracle之後,我們要明白,通常情況下我們的OS進程只能訪問4g以下的空間,redhat linux AS 2.1 或者AS3.0版本例外,他們可以提供VLM(Very large memory)功能支援,使得通過轉換可以使用36bit來標誌記憶體位址,那麼就是2的36次方理論上最大可支援64g記憶體訪問。在oracle中,則是通過將記憶體當作檔案來訪問的,虛擬一個 /dev/shm 的檔案系統,這個檔案系統是完全由記憶體組成的,這樣將突破4g的限制。那回過來我們看看,既然進程可以訪問4g以下記憶體為何通常SGA又是1.7g呢。
在OS中,規定了一個進程在應用程式中,能訪問的虛擬記憶體空間為0--3g,而3g--4g這段虛擬位址空間是保留給kernel使用的。要注意我們這裡強調的是虛擬位址空間,並沒有說物理地址空間,也就是說,假設有8g的記憶體,這0--3g的虛擬位址空間可能出現在8g記憶體的3g--8g部分記憶體段,並不是說是實體記憶體的0--3g段。而在這0--3g的虛擬位址中,oracle又是如何來使用的呢,這是固定好了地址的。
+++++++++++++++ 4g
+ +
+ +
+ +
+++++++++++++++ 3g: kernel
+ +
+ +
+ +
+++++++++++++++ 2g:process stack
+ +
+ +
+++++++++++++++ 1.25g: SGA起點
+++++++++++++++ 1g: oracle 共用庫裝載起點
+ +
+ +
+ +
+++++++++++++++ 0g:oracle program(可執行代碼)裝載起點
在這段虛擬位址的分配中,1.25g是sga的起點,而進程的私人空間的分配(stack部分)卻是從靠近3g處開始的。也就是實際上SGA和進程私人空間是共用了1.25g---3g這部分的,由於進程私人空間特別小,通常我們習慣性地認為SGA可以達到1.7g。進程私人空間有0.05g足夠了。從oracle一啟動開始,或者從任何一使用者進程登陸開始,所有虛擬位址的分配都已經固定好了,只有使用者私人空間還可以擴充。我們來看一下資料庫啟動後pmon進程(實際上任何一個進程都是一樣的)的虛擬位址分配情況。由於我一台機器上跑著2個資料庫,所以我們看其中一個,先看看資料庫SGA相關資訊
[root@ocnsb1 root]# su - oracle
[oracle@ocnsb1 oracle]$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.4.0 - Production on Mon Jul 26 11:37:23 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Real Application Clusters, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
select">sys@OCN>select INSTANCE_NAME from v$instance ;
INSTANCE_NAME
----------------
roocn1
show">sys@OCN>show sga
Total System Global Area 437327188 bytes
Fixed Size 451924 bytes
Variable Size 301989888 bytes
Database Buffers 134217728 bytes
Redo Buffers 667648 bytes
sys@OCN>
exit">sys@OCN>exit
Disconnected from Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Real Application Clusters, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
[oracle@ocnsb1 oracle]$ ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x73a32bdc 131072 oracle 640 457179136 50
0x84cc76ac 163841 oracle 640 1379926016 90
------ Semaphore Arrays --------
key semid owner perms nsems status
0x8df96364 622592 oracle 640 64
0x53609d64 753665 oracle 640 504
------ Message Queues --------
key msqid owner perms used-bytes messages
[oracle@ocnsb1 oracle]$
我這裡的共用記憶體段只有一個,並且就是SGA的大小(shmid為131072)。這是因為shnmax設定太大的緣故
[oracle@ocn2 kernel]$ more /proc/sys/kernel/shmmax
3221225472
[oracle@ocn2 kernel]$
接下來我們看看PMON資訊,首先要找到pmon進程號,然後去 /proc/pid/maps 中看該進程的虛擬位址分配資訊
[oracle@ocnsb1 oracle]$ ps -ef|grep pmon
oracle 13655 1 0 Jul24 ? 00:00:00 ora_pmon_roocn1
oracle 13926 1 0 Jul24 ? 00:00:00 ora_pmon_ocn1
oracle 31435 31092 0 11:51 pts/3 00:00:00 grep pmon
[oracle@ocnsb1 oracle]$
[oracle@ocnsb1 oracle]$ more /proc/13655/maps
08048000-0a4ba000 r-xp 00000000 08:05 681621 /opt/oracle/products/9.2.0/bin/oracle
0a4ba000-0ad54000 rw-p 02471000 08:05 681621 /opt/oracle/products/9.2.0/bin/oracle
0ad54000-0ae07000 rwxp 00000000 00:00 0
這部分是oracle program裝載資訊,我們可以看到空間使用了0--0ae07000 ,這部分大小不足256MB
40000000-40016000 r-xp 00000000 08:02 448102 /lib/ld-2.2.4.so
這是oracle 共用庫裝載的起點,0x40000000 正好是1g
40016000-40017000 rw-p 00015000 08:02 448102 /lib/ld-2.2.4.so
40017000-40018000 rw-p 00000000 00:00 0
40018000-40019000 r-xp 00000000 08:05 308464 /opt/oracle/products/9.2.0/lib/libodmd9.so
40019000-4001a000 rw-p 00000000 08:05 308464 /opt/oracle/products/9.2.0/lib/libodmd9.so
4001a000-40026000 r-xp 00000000 08:05 308345 /opt/oracle/products/9.2.0/lib/libskgxp9.so
40026000-4002a000 rw-p 0000b000 08:05 308345 /opt/oracle/products/9.2.0/lib/libskgxp9.so
4002a000-40038000 r-xp 00000000 08:05 308461 /opt/oracle/products/9.2.0/lib/libskgxn9.so
40038000-40039000 rw-p 0000d000 08:05 308461 /opt/oracle/products/9.2.0/lib/libskgxn9.so
40039000-4004d000 rw-p 00000000 00:00 0
4004d000-4032c000 r-xp 00000000 08:05 308455 /opt/oracle/products/9.2.0/lib/libjox9.so
4032c000-4043c000 rw-p 002de000 08:05 308455 /opt/oracle/products/9.2.0/lib/libjox9.so
4043c000-4043e000 rw-p 00000000 00:00 0
4043e000-40441000 r-xp 00000000 08:02 448115 /lib/libdl-2.2.4.so
40441000-40442000 rw-p 00002000 08:02 448115 /lib/libdl-2.2.4.so
40442000-40443000 rw-p 00000000 00:00 0
40443000-40465000 r-xp 00000000 08:02 448117 /lib/libm-2.2.4.so
40465000-40466000 rw-p 00021000 08:02 448117 /lib/libm-2.2.4.so
40466000-40475000 r-xp 00000000 08:02 448147 /lib/libpthread-0.9.so
40475000-4047d000 rw-p 0000e000 08:02 448147 /lib/libpthread-0.9.so
4047d000-40490000 r-xp 00000000 08:02 448120 /lib/libnsl-2.2.4.so
40490000-40491000 rw-p 00012000 08:02 448120 /lib/libnsl-2.2.4.so
40491000-40493000 rw-p 00000000 00:00 0
40493000-40494000 r-xp 00000000 08:02 352330 /usr/lib/libaio.so.1
40494000-40495000 rw-p 00000000 08:02 352330 /usr/lib/libaio.so.1
40495000-405ca000 r-xp 00000000 08:02 448111 /lib/libc-2.2.4.so
405ca000-405cf000 rw-p 00134000 08:02 448111 /lib/libc-2.2.4.so
405cf000-405d3000 rw-p 00000000 00:00 0
405d3000-405d4000 r-xp 00000000 08:02 146106 /lib/libredhat-kernel.so.1.0.1
405d4000-405d5000 rw-p 00000000 08:02 146106 /lib/libredhat-kernel.so.1.0.1
405d5000-405f9000 rw-p 00000000 00:00 0
405fa000-40604000 r-xp 00000000 08:02 448136 /lib/libnss_files-2.2.4.so
40604000-40605000 rw-p 00009000 08:02 448136 /lib/libnss_files-2.2.4.so
40605000-40685000 rw-p 00000000 08:02 69445 /dev/zero
40685000-406c6000 rw-p 00000000 00:00 0
共用庫消耗了不到20MB的空間
50000000-6b000000 rw-s 00000000 00:04 131072 /SYSV73a32bdc (deleted)
這是SGA的起點,0x50000000 表示1.25g
6b000000-6b001000 r--s 1b000000 00:04 131072 /SYSV73a32bdc (deleted)
6b001000-6b0a2000 rw-s 1b001000 00:04 131072 /SYSV73a32bdc (deleted)
6b0a2000-6b0a3000 r--s 1b0a2000 00:04 131072 /SYSV73a32bdc (deleted)
6b0a3000-6b400000 rw-s 1b0a3000 00:04 131072 /SYSV73a32bdc (deleted)
sga虛擬空間分配到這裡,通過計算16進位數,正好和我們的SGA大小吻合,131072就是我們在ipcs查看的時候的 shmid
bffe5000-bffee000 rwxp ffff8000 00:00 0
bfff0000-bfff1000 r-xs 00000000 08:02 69304 /dev/vsys
由於0xc0000000正好是3g(16進位數c=12,4*3=12,0x40000000表示1g),則這裡表示進程私人空間的分配的起點。查看oracle任何一個使用者登陸進程也將發現這樣的虛擬位址分配。在這裡我們很容易看出來,oracle program 和共用記憶體庫所佔用的空間很小,沒有必要給那麼大,實際上,oracle program 給256M足夠安全,而共用庫給50M也足夠安全了,也就是從理論上來講,我們可以把oracle program所需要壓縮在0x10000000以下,共用庫所需要記憶體壓縮在0x12000000以下,這樣SGA的起點就可以提升到0x12000000(0.3g)。而原來是從0x5000000(1.25g)開始的,只有大約1.7g分配給SGA,現在從0.3g開始分配SGA則可以接近2.7g,比如分配2.65g記憶體給SGA。要實現這個功能,我們需要重新編譯oracle program,降低共用庫虛擬記憶體分配的地址和SGA的分配起點位置。0x4000000這個共用庫裝載的起點,是由進程的mapped_base來決定的
[oracle@ocnsb1 oracle]$ more /proc/13655/mapped_base
1073741824
這個大小是1G,則意味著共用庫的裝載從虛擬位址的1g位置開始,如果要降低這個地址,需要在oracle啟動之前,也就是用root使用者把將啟動oracle的進程的mapped_base降低到256M,這樣oracle啟動之後的產生的進程都將繼承這個值。
su - root echo 268435456 > /proc//mapped_base
當然我們也可以通過一些shell來實現oracle使用者登陸之後自動降低mapped_base的功能,這個在google上就能找到了,或者參考
http://www.puschitz.com/TuningLinuxForOracle.shtml#IncreasingSpaceForLargerSGA 中文章內容如下
Giving Oracle Users the Privilege to Change the Base Address for Oracle's Shared Libraries Without Giving them root Access
As shown above, only root can change the base address "mapped base" for shared libraries. Using sudo we can give Oracle users the privilege to change "mapped base" for their own shells without giving them full root access. Here is the procedure:
su - root
# E.g. create a script called "/usr/local/bin/ChangeMappedBase"
# which changes the "mapped base" for the parent process,
# the shell used by the Oracle user where the "sudo" program # is executed (forked). Here is an example:
#/bin/sh
# Lowering "mapped base" to 0x10000000 echo 268435456 > /proc/$PPID/mapped_base
# Make sure that owernship and permissions are correct chown root.root /usr/local/bin/ChangeMappedBase
chmod 755 /usr/local/bin/ChangeMappedBase
# Allow the Oracle user to execute /usr/local/bin/ChangeMappedBase via sudo echo "oracle ALL=/usr/local/bin/ChangeMappedBase" >> /etc/sudoers
Now the Oracle user can run /usr/local/bin/ChangeMappedBase to change "mapped base" for it's own shell:
$ su - oracle
$ cat /proc/$$/mapped_base; echo 1073741824
$ sudo /usr/local/bin/ChangeMappedBase Password:
# type in the password for the Oracle user account
$ cat /proc/$$/mapped_base; echo 268435456 $
When /usr/local/bin/ChangeMappedBase is executed the first time after an Oracle login, sudo will ask for a password. The password that needs to be entered is the password of the Oracle user account.
Changing the Base Address for Oracle's Shared Libraries Automatically During an Oracle Login
The procedure in the previous section asks for a password each time /usr/local/bin/ChangeMappedBase is executed the first time after an Oracle login. To have "mapped base" changed automatically during an Oracle login without a password, the following can be done:
Edit the /etc/sudoers file with visudo:
su - root visudo
Change the entry in /etc/sudoers from:
oracle ALL=/usr/local/bin/ChangeMappedBase
to read:
oracle ALL=NOPASSWD: /usr/local/bin/ChangeMappedBase
Make sure bash executes /usr/local/bin/ChangeMappedBase during the login process. You can use e.g. ~oracle/.bash_profile:
su - oracle echo "sudo /usr/local/bin/ChangeMappedBase" >> ~/.bash_profile
The next time you login to Oracle, the base address for shared libraries will bet set automatically.
$ ssh oracle@localhost
oracle@localhost's password: Last login: Sun Apr 6 13:59:22 2003 from localhost
$ cat /proc/$$/mapped_base; echo 268435456 $
SGA起點從1.25g降低到0.3g則需要重新編譯oracle program。必須要強調的是,SGA的起點是和共用庫的起點mapped_ase相關的,SGA的起點至少得大於共用庫的起點0.05g以上才是安全的,否則資料庫將不能啟動或者崩潰。
關閉oracle
su - oracle
cd $ORACLE_HOME/rdbms/lib
修改共用庫裝載地址的檔案定義
genksms -s 0x12000000 > ksms.s
編譯好目標檔案
make -f ins_rdbms.mk ksms.o
重新編譯oracle可執行檔
make -f ins_rdbms.mk ioracle
至於 redhat linux AS 2.1以上版本 oracle的VLM的使用則也是比較簡單的了,參考
http://www1.ap.dell.com/content/topics/topic.aspx/ap/topics/power/zhcn/ps3q03_mahmood?c=cn&l=zh&s=bsd
http://otn.oracle.com/global/cn/pub/notes/technote_rhel3.html
當然,internet上還有更多文章可以供參考。
在這裡我要指出一個問題,也是我們在實踐中遇到的一個問題,那就是,若SGA分配的很大,但沒有使用VLM,幾乎很靠近3g的時候,大約只留下20m左右。這樣當一個進程進行hash join,由於我們的pga_aggregate_target設定為1g,oracle預設單個進程使用PGA可以達到pga_aggregate_target * 5% = 50M,則使得在進行hash join的時候出錯
ORA-04030: out of process memory when trying to allocate 254476 bytes (hash-join subh,kllcqas:kllsltba)
我們調整pga_aggregate_target減小到400M則該查詢執行成功。因為沒有使用VLM的情況下單個進程的記憶體配置空間必須在3g以下,而PGA的分配也屬於這個範疇。如果使用VLM則PGA已經被分配到4g以上部分的虛擬位址,不再有這個問題。在此不再對VLM進行過多的闡述,因為使用也比較簡單,從原理上來講就是通過os擴充32bit 到36bit,oracle使用檔案來管理記憶體,並支援進程訪問4g以上部分的虛擬記憶體。linux上這種用法得到推廣的根本原因是因為其64bit oracle很少被使用,其他如sunOS/hp unix/AIX 等都廣泛使用64bit oracle了,這些方法也就失去價值了。
關於PGA和SGA的關係,更多內容請參考
32bit oracle中SGA_MAX_SIZE 與 單個進程 PGA 的制約關係