一旦地址空间被用户会话占满了后,如果要再创建一个新会话,就会存在无法分配到地址空间的危险。将可能报以下错误:
ORA-12500 / TNS-12500
TNS:listener failed to start a dedicatedserver process
也可能报这些错误:
o ORA-12540 / TNS-12540 TNS:internal limit restriction exceeded
o NT-8 Not enough storage is available to process this command
o skgpspawn failed:category = ....
o ORA-27142 could not create new process
o ORA-27143 OS system call failure
o ORA-4030 out of process memory when trying to allocate ....
因为地址空间碎片问题和DLL被载入了oracle服务进程的地址空间,这些错误很可能发生再当Oracle进程占用大概1.6G~1.7G(可以通过任务管理器或TopShow查看)时。
2.4.4.1.会话内存大小设置
我们前面说了,一个进程的全部内存大小被限制在2G以内。因此,对于一个有许多用户同时访问的系统,要考虑这些会话总内存小于2G - SGA的大小。
下列参数会影响每个会话的内存大小(这些参数前面都有介绍):
o bitmap_merge_area_size
o create_bitmap_area_size
o hash_area_size
o open_cursors
o sort_area_size (sort_area_retained_size)
在没有设置PGA_AGGREGATE_TARGE(这个参数能尽量但不一定使所有会话PGA之和在指定范围内)参数时,需要调整这些参数,以使所有会话占用内存与SGA之和小于2G。过多的使用PL/SQL结构体(如PL/SQLTABLE、ARRAY)也会导致会话内存增大。
2.4.4.2.ORASTACK修改线程堆栈大小
Oracle提供了ORASTACK工具让用户内修改Oracle执行程序创建会话、线程时的默认堆栈大小。当ORASTACK应用于一个可执行程序时,它会修改程序头部的、定义使用创建线程API函数所指定默认堆栈大小的二进制区,以修改默认堆栈的大小。没有必要去修改线程提交页数的默认值,因为它们是从堆栈中请求到的。当用户非常多时,通过减少每个创建在Oracle中会话堆栈大小,可以节省大量内存。比如,一个1000用户的系统,将堆栈从1M降为500K后,能节省出1000 *500K = 500M的地址空间。
在需要使用ORASTACK来降低现场堆栈大小时,你需要测试你的系统以保证新的堆栈大小能确保系统正常运行。如果堆栈大小被缩小到Oracle服务端所必须的堆栈大小以下,就会产生堆栈溢出错误,用户进程就失败(通常报ORA-3113错误),并且在alert log中不会有报错而且页不产生trace文件。Oracle一般不推荐将堆栈改到500K以下(尽管不少系统在300K时也能正常运行)。
ORASTACK必须修改所有能在oracle中创建线程的进程,使用语法如下:
orastack executable_name new_stack_size_in_bytes
下面的例子将堆栈改为500K:
orastack oracle.exe 500000
orastack tnslsnr.exe 500000
orastack svrmgrl.exe 500000
orastack sqlplus.exe 500000
在使用ORASTACK之前必须保证没有任何oracle进程正在运行。
此外,如果有程序在本地连接(没有通过SQL*NET)到Oracle,也要先停止(如在本地运行sqlplus连接了实例)。
2.4.4.3.会话内存如何释放、线程如何结束
当会话成功结束后,它会按用Win32 API函数VirtualFree来释放它的内存,调用此函数时,需要指定MEM_DECOMMIT | MEM_RELEASE标识。当所有内存被释放后,堆栈也被释放,将Oracle进程中指向完成的会话的地址空间空闲出来。
如果一个用户会话被异常结束,它将不会释放它所分配的内存,这些内存页会被继续保留在Oracle进程的地址空间中,直到进程结束。会话的异常结束可能由以下原因导致的:
oShutdown abort.
oAlter session kill session.
oorakill杀掉的会话.
o Oracle管理助手for Windows:kill session.
o其他杀线程的工具(TopShow工具提供了杀线程的功能)
Oracle建议尽量少使用以上方式(命令),特别是shutdown abort(这种停止实例的方法所带来的问题还不止这个)。当调用shutdown abort时,Oracle会调用Win32 API函数TerminateThread来中止每个用户会话,这个命令将直接杀掉线程而不释放它们的内存。如果系统已经接近2G地址空间的限制,Oracle实例再次启动要分配内存时就会产生问题。唯一释放Oracle全部内存的方法是停止和启动Oracle服务(服务OracleService
如果windows NT下的系统需要能被许多用户访问,可以通过以下措施来优化内存的使用:
o降低相关的PGA、UGA内存参数(如SORT_AREA_SIZE);
o降低SGA的参数;
o使数据库作业队列数(参数job_queue_processes控制)和并行查询slave(参数parallel_max_servers控制)最小,因为它们也会导致Oracle进程创建线程;
o使用ORASTACK降低会话、线程堆栈大小到500K;
o考虑使用MTS模式;
o考虑将Windows NT升级到Windows NT企业版;
o考虑升级硬件以支持Intel ESMA(Extended. ServerMemory Architecture,扩展服务内存架构)