前几日,东区某客户的19c rac出现了ORA-04030,从报错的trace来看,使用了32g的PGA,对于单进程内存上限众说纷纭,有很多不同意见,有些说2g、有些说4g。。。,本篇文章就深入分析一下oracle进程内存上限。
说到PGA不得不关联到UGA和CGA,下面参考个人觉得写得很好的blog,对PGA、UGA、CGA进行了详细的概述。
https://blog.titanwolf.in/a?ID=01450-1639cbbd-7123-4e8c-afe0-4d8899dd8951
The Process Global Area (PGA) can be understood as either Process Global Area or Program Global Area. Its memory segment is in the Process Private Memory instead of Shared Memory. It is a global area It means that it contains all the global variables and data structures that the code may enter, but it is not shared by all processes. Each Oracle server process contains its own PGA, which only contains the specific related to the process Information. The structure in the PGA does not need to be protected by latches, because other processes cannot enter it to access it.
The PGA contains information about the operating system resources that the process is using and the state of the process, while the Oracle shared resources used by other processes are in the SGA. PGA is private rather than shared, this mechanism is necessary , Because these resources can be cleared and released when the process dies.
PGA contains two main areas: Fixed PGA and Variable PGA or PGA Heap.The role of Fixed PGA is similar to Fixed SGA, and both contain atomic variables (inseparable), small data structures and pointers to Variable PGA.
Variable PGA is a heap. Its Chunks can be viewed from the Fixed Table X$KSMPP. The structure of this table is the same as the X$KSMSP mentioned earlier. PGA HEAP contains some permanent memory related to the Fixed Table. It It is dependent on the settings of some parameters. These parameters include DB_FILES, LOG_FILES, CONTROL_FILES.
UGA (User Global Area) contains information about a specific session, including the following:
- The duration and runtime area of the opened cursor
- Package status information, specific variables
- Java session state
- Available ROLES
- Tracking events that are ENABLE
- Effective NLS parameter settings
- Open DBLINK
- Conversation entry control
Like PGA, UGA is also composed of two areas: Fixed UGA and Variable UGA, also known as UGA HEAP.Fixed UGA contains about 70 atomic variables, small data structures and pointers to Variable UGA.
Chunks in UGA HEAP can obtain relevant information from their own sessions by looking at the table X$KSMUP. The structure of this table is the same as X$KSMSP. UGA HEAP contains some permanent memory segments related to fixed tables, and some The settings of the parameters are dependent. These parameters are OPEN_CURSORS, OPEN_LINKS, and MAX_ENABLE_ROLES.
The location of UGA in memory depends on the configuration mode of the session. If the configuration mode of the session connection is dedicated server mode (DDS), that is, a session corresponds to a process, UGA is placed in the PGA. In the PGA, Fixed UGA is One of them is a Chunk, and UGA HEAP is a subheap of PGA. If the session connection is configured as shared server mode (MTS), Fixed UGA is a Chunk in the SHARED POOL, and UGA HEAP is in the SHARED POOL Subheap
Unlike other global areas, the Call Global Area exists temporarily. It only exists during the call to the data, generally when the lowest-level call to the instance requires CGA, as follows:
- Analyze a SQL statement
- Execute a SQL statement
- To take out the output of a SELECT statement,
a single CGA is needed for recursive calls. During the analysis of the SQL statement, the recursive call to the data dictionary information is needed, because the SQL statement is grammatically analyzed, and the statement During the optimization period, the execution plan must be calculated. When the PL/SQL block is executed, the execution of the SQL statement is also required to be recursively called, and the trigger execution is also required to be processed when the DML statement is executed.
Regardless of whether UGA is placed in the PGA or in the SGA, CGA is a subheap of the PGA. An important inference of this fact is that the session must be a process during a call. For an Oracle database process in an MTS Understanding this point during application development is very important. If there are more calls, the number of processes must be increased to accommodate the increase in calls.
Without the data structure in CGA, CALLS cannot work. In fact, the data structure related to a CALL is generally placed in UGA, such as SQL AREA, PL/SQL AREA and SORT AREA, they must all be in UGA. Because they must always exist and be available between the CALLS. The data structure contained in the CGA must be released after a CALL. For example, the CGA contains information about recursive calls, direct I/O BUFFER, etc. There are other temporary data structures.
对于PGA上限值,首先需要说明的是“_smm_max_size”和“_pga_max_size”非常具有迷惑性,它们仅仅与PGA自动管理时的workarea部分相关。同时 _pga_max_size和 _smm_max_size 的值与pga_aggregate_target也关系密切。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
SQL> @sp pga_max -- show parameter by sp -- show hidden parameter by sp old 3: where x.indx=y.indx and ksppinm like '_%&p%' new 3: where x.indx=y.indx and ksppinm like '_%pga_max%' NAME VALUE DESC ---------------------------------------- ---------- ------------------------------------------------------------------------------------------ _pga_max_size 209715200 Maximum size of the PGA memory for one process SQL> @sp smm_max -- show parameter by sp -- show hidden parameter by sp old 3: where x.indx=y.indx and ksppinm like '_%&p%' new 3: where x.indx=y.indx and ksppinm like '_%smm_max%' NAME VALUE DESC ---------------------------------------- ---------- ------------------------------------------------------------------------------------------ _smm_max_size_static 102400 static maximum work area size in auto mode (serial) _smm_max_size 102400 maximum work area size in auto mode (serial) |
对于UGA和CGA的内存分配,oracle在9.2开始,使用Real-Free Memory Allocator,这样的好处是使用完成之后可以立即释放给操作系统,在11g中, Real-Free Memory Allocator 的分配机制是每次分配参数“_realfree_heap_pagesize_hint”的page size,默认为65536。在12c以上版本参数名字改为了“ _realfree_heap_pagesize ”
1 2 3 4 5 6 7 8 9 10 11 12 13 |
SQL> @sp realfree_heap -- show hidden parameter by sp old 3: where x.indx=y.indx and ksppinm like '_%&p%' new 3: where x.indx=y.indx and ksppinm like '_%realfree_heap%' NAME VALUE DESC ---------------------------------------- ---------- ------------------------------------------------------------------------------------------ _realfree_heap_max_size 4096 minimum max total heap size, in Kbytes _realfree_heap_pagesize_hint 65536 hint for real-free page size in bytes _realfree_heap_mode 0 mode flags for real-free heap _use_realfree_heap TRUE use real-free based allocator for PGA memory |
通过strace也可以验证每次分配内存都是使用 “_realfree_heap_pagesize_hint” 大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
--exec proc_test; 5224 23:12:09.946525 (+ 0.000103) mmap(0x7f7cc855c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc855c000 5224 23:12:09.946754 (+ 0.000229) mmap(0x7f7cc856c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc856c000 5224 23:12:15.087795 (+ 0.000216) mmap(0x7f7cc848c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc848c000 5224 23:12:15.087913 (+ 0.000118) mmap(0x7f7cc849c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc849c000 5224 23:12:15.087955 (+ 0.000040) mmap(0x7f7cc84ac000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc84ac000 5224 23:12:15.087995 (+ 0.000040) mmap(0x7f7cc84bc000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc84bc000 5224 23:12:15.088035 (+ 0.000039) mmap(0x7f7cc84cc000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc84cc000 5224 23:12:15.088074 (+ 0.000039) mmap(0x7f7cc84dc000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc84dc000 5224 23:12:15.088113 (+ 0.000039) mmap(0x7f7cc84ec000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc84ec000 5224 23:12:15.088152 (+ 0.000039) mmap(0x7f7cc84fc000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc84fc000 5224 23:12:15.088191 (+ 0.000039) mmap(0x7f7cc850c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc850c000 5224 23:12:15.088230 (+ 0.000038) mmap(0x7f7cc851c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc851c000 5224 23:12:15.088272 (+ 0.000041) mmap(0x7f7cc852c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc852c000 5224 23:12:15.088311 (+ 0.000039) mmap(0x7f7cc853c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc853c000 5224 23:12:15.088370 (+ 0.000060) mmap(0x7f7cc854c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc854c000 5224 23:12:15.088412 (+ 0.000040) mmap(0x7f7cc855c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc855c000 5224 23:12:15.088453 (+ 0.000040) mmap(0x7f7cc856c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc856c000 5224 23:12:15.088491 (+ 0.000038) mmap(0x7f7cc857c000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc857c000 5224 23:12:15.088532 (+ 0.000040) mmap(0x7f7cc7fac000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc7fac000 5224 23:12:15.088571 (+ 0.000039) mmap(0x7f7cc7fbc000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc7fbc000 5224 23:12:15.088612 (+ 0.000040) mmap(0x7f7cc7fcc000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc7fcc000 5224 23:12:15.088651 (+ 0.000039) mmap(0x7f7cc7fdc000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc7fdc000 5224 23:12:15.088691 (+ 0.000040) mmap(0x7f7cc7fec000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc7fec000 5224 23:12:15.088732 (+ 0.000041) mmap(0x7f7cc7ffc000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 6, 0) = 0x7f7cc7ffc000 |
每次分配进程都会持有一个虚拟内存的map,而每个进程能持有的最大map数量由vm. max_map_count 控制,默认为65530
1 2 |
[root@rac1 FIL_PAGE_INDEX]# sysctl -a|grep max_map_count vm.max_map_count = 65530 |
所以在11g当中,所有参数默认的情况下,进程能持有的最大内存是 max_map_count * _realfree_heap_pagesize_hint =4G。
但是如果不使用 Real-Free Memory Allocator 去分配内存的话,即“_use_realfree_heap”为false时,就与“ _realfree_heap_pagesize_hint ”无关了,此时每次分配的内存依然一致,是以“ _uga_cga_large_extent_size ”为大小去分配,默认为 262144 。
1 2 3 4 5 6 7 8 9 10 11 |
SQL> @sp uga_cga -- show parameter by sp -- show hidden parameter by sp old 3: where x.indx=y.indx and ksppinm like '_%&p%' new 3: where x.indx=y.indx and ksppinm like '_%uga_cga%' NAME VALUE DESC ---------------------------------------- ---------- ------------------------------------------------------------------------------------------ _uga_cga_large_extent_size 262144 UGA/CGA large extent size |
同样通过strace跟踪可以验证,这样的话理论上的内存上限为 max_map_count * _uga_cga_large_extent_size =16G,但是这一点我不敢确认,因为我的测试环境内存太小无法验证。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
SQL> alter system set "_use_realfree_heap"=false scope=spfile; System altered. SQL> startup force ORACLE instance started. Total System Global Area 1653518336 bytes Fixed Size 2253784 bytes Variable Size 1258294312 bytes Database Buffers 385875968 bytes Redo Buffers 7094272 bytes Database mounted. Database opened. SQL> exec proc_test; 19588 01:44:32.467219 (+ 0.003174) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c405f1000 19588 01:44:32.470199 (+ 0.002978) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c405b1000 19588 01:44:32.473362 (+ 0.003164) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40571000 19588 01:44:32.476684 (+ 0.003321) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40531000 19588 01:44:32.479697 (+ 0.003014) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c404f1000 19588 01:44:32.482506 (+ 0.002808) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c404b1000 19588 01:44:32.496107 (+ 0.002945) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40471000 19588 01:44:32.498582 (+ 0.002474) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40431000 19588 01:44:32.505108 (+ 0.006537) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c403f1000 19588 01:44:32.507839 (+ 0.002729) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c403b1000 19588 01:44:32.510222 (+ 0.002377) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40371000 19588 01:44:32.512627 (+ 0.002404) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40331000 19588 01:44:32.514859 (+ 0.002229) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c402f1000 19588 01:44:32.520255 (+ 0.005396) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c402b1000 19588 01:44:32.522856 (+ 0.002604) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40271000 19588 01:44:32.525000 (+ 0.002144) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40231000 19588 01:44:32.527099 (+ 0.002093) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c401f1000 19588 01:44:32.529096 (+ 0.001998) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c401b1000 19588 01:44:32.531075 (+ 0.001978) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40171000 19588 01:44:32.532995 (+ 0.001919) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40131000 19588 01:44:32.534915 (+ 0.001920) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c400f1000 19588 01:44:32.536835 (+ 0.001920) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c400b1000 19588 01:44:32.538724 (+ 0.001888) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40071000 19588 01:44:32.540489 (+ 0.001765) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c40031000 19588 01:44:32.542357 (+ 0.001867) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c3fff1000 19588 01:44:32.544122 (+ 0.001808) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c3ffb1000 19588 01:44:32.545975 (+ 0.001809) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c3ff71000 19588 01:44:32.547685 (+ 0.001711) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c3ff31000 19588 01:44:32.549229 (+ 0.001542) mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2c3fef1000 |
回到案例,那么为什么在19c中,所有参数都是默认的情况下,PGA内存达到了32G之后才报出ORA-04030呢?我们看看报错的trace文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
Jump to table of contents Dump continued from file: /oracle/diag/rdbms/d4testdb01_std/d4testdb01/trace/d4testdb01_j000_181338.trc [TOC00001] ORA-04030: 在尝试分配 16296 字节 (koh-kghu sessi,pl/sql vc2) 时进程内存不足 [TOC00001-END] [TOC00002] ========= Dump for incident 948992 (ORA 4030) ======== [TOC00003] ----- Beginning of Customized Incident Dump(s) ----- ======================================= TOP 10 MEMORY USES FOR THIS PROCESS --------------------------------------- *** 2021-12-02T01:42:33.752825+08:00 87% 28 GB, 1823383 chunks: "pl/sql vc2 " PL/SQL koh-kghu sessi ds=0x7f14ca3eab90 dsprt=0x7f14caf99568 13% 4115 MB, 264755 chunks: "pmucalm coll " PL/SQL koh-kghu sessi ds=0x7f14ca3eab90 dsprt=0x7f14caf99568 1% 172 MB, 32828 chunks: "free memory " PL/SQL koh-kghu sessi ds=0x7f14ca3eab90 dsprt=0x7f14caf99568 0% 5402 KB, 90 chunks: "kllcqas:kllsltba " SQL kxs-heap-w ds=0x7f14ca704a70 dsprt=0x7f14caf99568 0% 3923 KB, 1358 chunks: "free memory " session heap ds=0x7f14caf99568 dsprt=0x7f14cfe57e00 0% 1024 KB, 1 chunk : "kcbpioqInitClie " SQL kxs-heap-w ds=0x7f14ca704a70 dsprt=0x7f14caf99568 0% 744 KB, 190 chunks: "ksipc pga chnk " pga heap ds=0x7f14cfe55220 dsprt=(nil) 0% 468 KB, 1 chunk : "NOSYNC FOB ptr " pga heap ds=0x7f14cfe55220 dsprt=(nil) 0% 433 KB, 107 chunks: "kxsFrame4kPage " session heap ds=0x7f14caf99568 dsprt=0x7f14cfe57e00 0% 316 KB, 1 chunk : "kllcqc:kllcqslt " SQL kxs-heap-w ds=0x7f14ca704a70 dsprt=0x7f14caf99568 ======================================= PRIVATE MEMORY SUMMARY FOR THIS PROCESS --------------------------------------- ****************************************************** PRIVATE HEAP SUMMARY DUMP 32 GB total: 32 GB commented, 1756 KB permanent 323 KB free (0 KB in empty extents), 32 GB, 1 heap: "session heap " 128 KB free held ------------------------------------------------------ Summary of subheaps at depth 1 32 GB total: 32 GB commented, 201 KB permanent 3983 KB free (0 KB in empty extents), 32 GB, 22 heaps: "koh-kghu sessi " 3187 KB free held *** 2021-12-02T01:42:34.809433+08:00 ------------------------------------------------------ Summary of subheaps at depth 2 32 GB total: 32 GB commented, 1155 KB permanent 172 MB free (0 KB in empty extents), 28 GB, 1823383 chunks: "pl/sql vc2 " 150 MB free held 4136 MB, 264755 chunks: "pmucalm coll " 22 MB free held *** 2021-12-02T01:42:35.270640+08:00 ****************************************************** KGH STACK DUMP Stack allocations ----------------- Skipped 3 chunks under 10240 bytes with total size 7694 bytes ========================================= REAL-FREE ALLOCATOR DUMP FOR THIS PROCESS ----------------------------------------- Dump of Real-Free Memory Allocator Heap [0x7f14caf57000] mag=0xfefe0001 flg=0x5000007 fds=0x0 blksz=65536 blkdstbl=0x7f14caf57018, iniblk=524288 maxblk=524288 numsegs=321 In-use num=1427 siz=34225389568, Freeable num=21 siz=6488064, Free num=2 siz=9240576 Client alloc 34231877632 Client freeable 6488064 |
可以看到 blksz还是65536,但是PGA确实达到了32G之后报出了ORA-04030,搜索Process Map Dump可以看到仅仅使用了四百多个map就达到了32G的内存,充分说明每次分配的大小并不是65536。
1 2 3 |
行 7279: ----- Process Map Dump ----- 行 7746: *********************** End of process map dump **************** |
查看具体的map信息发现,有些map映射的虚拟内存空间非常大达到了 256M。这是怎么回事呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
7f0ce10ca000-7f0cf10da000 rw-p 00000000 00:00 0 7f0cf10da000-7f0d010ea000 rw-p 00000000 00:00 0 7f0d010ea000-7f0d110fa000 rw-p 00000000 00:00 0 7f0d110fa000-7f0d2110a000 rw-p 00000000 00:00 0 7f0d2110a000-7f0d3111a000 rw-p 00000000 00:00 0 7f0d3111a000-7f0d4112a000 rw-p 00000000 00:00 0 7f0d4112a000-7f0d5113a000 rw-p 00000000 00:00 0 7f0d5113a000-7f0d6114a000 rw-p 00000000 00:00 0 7f0d6114a000-7f0d7115a000 rw-p 00000000 00:00 0 .... SQL> select to_number('7f0cf10da000','xxxxxxxxxxxxxxxxxxxxxxxxx')-to_number('7f0ce10ca000','xxxxxxxxxxxxxxxxxxxxxxxxxxx') from dual; TO_NUMBER('7F0CF10DA000','XXXXXXXXXXXXXXXXXXXXXXXXX')-TO_NUMBER('7F0CE10CA000',' -------------------------------------------------------------------------------- 268500992 |
通过strace跟踪发现,19c的Real-Free Memory Allocator采用了一种动态分配的方式,有点类似data extent的auto管理方式。不确定12c是否是这种方式没有去验证。
1 2 3 4 5 6 7 8 9 10 11 |
[root@rac1 FIL_PAGE_INDEX]# grep "mmap" 1.log |grep -v "mmap(NULL"|grep -v "PROT_NONE"|awk -F',' '{print $2}'|uniq -c 72 65536 50 131072 50 262144 50 524288 50 1048576 50 2097152 50 4194304 50 8388608 50 16777216 。。。 |
可以看到初始分配大小仍然采用“ _realfree_heap_pagesize”进行分配,分配到大概50次之后开始进行调整,调整粒度是乘以2,一直递增下去,最大应该是能达到256M,这也是为什么19c的进程使用了如此少的map内存就能达到32g的原因,那么19c的内存上限与vm.map_max_count的设置就没有关系了,因为根本不需要65530那么多的map,进程内存就可以达到32g的进程内存上限。
那么19c PGA的内存上限由什么决定呢?从trace里面看个人猜测应该是 blksz * maxblk ,blksz就是参数” _realfree_heap_pagesize”,而 maxblk 并没有找到出处,从11g-19c的maxblk都是524288,应该是代码层面写死的,11g之所以只能达到4G的上限是因为统一分配的内存大小受到了vm.map_max_count(65530)的限制。而19c是动态分配的大小,并且都是” _realfree_heap_pagesize ”的整数倍,当 iniblk= maxblk 时,就会达到内存上限。
1 2 3 4 5 6 7 8 9 10 11 12 |
========================================= REAL-FREE ALLOCATOR DUMP FOR THIS PROCESS ----------------------------------------- Dump of Real-Free Memory Allocator Heap [0x7f14caf57000] mag=0xfefe0001 flg=0x5000007 fds=0x0 blksz=65536 blkdstbl=0x7f14caf57018, iniblk=524288 maxblk=524288 numsegs=321 In-use num=1427 siz=34225389568, Freeable num=21 siz=6488064, Free num=2 siz=9240576 Client alloc 34231877632 Client freeable 6488064 |
那么19c中,如何避免PGA使用如此32G大内存呢?
- resource manager 设置session_pga_limit
- event 10261