内存错误与内存瓶颈不同,当出现内存错误时,轻则某些特殊操作不能完成,重则整个sqlserver无响应,对sqlserver影响通常很大。

sqlserver常见的内存错误主要有以下三种:

  • 701 —— OOM(Out of Memory)
  • 8645 —— 语句运行时未及时申请到内存
  • 17189 —— sqlserver无法创建新线程供新连接使用

 

一、 701报错

当sqlserver需要申请一段stolen内存,却发现没有地址空间可供申请,错误日志里就会有701报错。

换句话说,701报错只针对stolen部分内存,代表stolen部分内存不足了。在64位机器上,sqlserver可用内存空间得到了巨大的扩展,再遇上701错误的概率很小,这个报错基本都发生在32位机器上。

错误日志中信息如下:

Error: 701, Severity: 17, State: 123.
There is insufficient system memory in resource pool 'internal' to runthis query.

在这条报错信息之前,还有一条信息指出sqlserver是在进行什么操作时遇到的701。

 

一般有以下两种场景:

1. multi-page地址段没有连续空间可供申请

SqlServer 内存篇(五)—— 常见内存错误与解决方法_错误日志

1)原因可能有以下两种:

multi-page确实已大量被使用,剩余空间不足

multi-page被大量使用有可能是因为sqlserver自己申请了太多,这些申请可以在memory clerk中跟踪到。在随701错误一起输出的memory status报告中,应该能够找到某个clerk申请了大量multi-page。

SqlServer 内存篇(五)—— 常见内存错误与解决方法_错误日志_02

multi-page中碎片过多

这种情况通常是第三方代码申请了大量内存。如果在errorlog里没有看到任何clerk申请了大量内存,就应该检查sqlserver是否有使用以下功能,导致第三方代码大量申请内存:

  • SQL CLR(尤其明显)
  • Linked Server
  • 使用sp_OACreate调用COM对象
  • Extended Stored Procedures

2)解决方法:

 multi-page内存压力分析部分

 

2. buffer pool中stolen内存申请不到

SqlServer 内存篇(五)—— 常见内存错误与解决方法_sql_03

buffer pool中stolen内存压力分析

SqlServer 内存篇(五)—— 常见内存错误与解决方法_错误日志_04

SqlServer 内存篇(五)—— 常见内存错误与解决方法_错误日志_05

 

二、 8645报错

通常发生在需要申请内存进行排序或hash等操作的查询,在规定时间内没能获得足够的内存。这里申请的内存一般都是buffer pool中的。

 

1. 报错特征

  • 错误日志中报错如下(最明显):
Msg 8645, Level 17, State 1, Procedure , Line 1
A time out occurred while waiting for memory resources to execute the query. Re-run the query.
  • sqlserver响应速度非常慢,严重影响业务
  • 部分登录请求无法完成,用户可能遇到login failed报错
  • 已连上的连接也可能遇到报错,错误信息不固定
  • 不少连接正在等待resource_semaphore事件
  • Memory Grants Pending计数器可能不为0

 

2. 常见原因

  • sqlserver已存在严重的内存压力,哪怕很小的内存申请也难以得到满足
  • sqlserver本来内存压力不太大,但客户端突然发过来一些极为复杂需大量消耗内存的语句

 

3. 排查思路

  • sqlserver是否独占服务器,是否有其他应用程序大量占用了内存
  • 检查sqlserver内存参数设置是否合理
  • 检查sqlserver当前运行语句及等待事件
  • 检查sys.dm_os_memory_clerks中个clerk内存申请及变化
  • 检查sys.dm_exec_query_resource_semaphores视图,了解每个查询资源信号量状态
select convert(varchar(30),getdate(),121) as runtime,
resource_semaphore_id,target_memory_kb,total_memory_kb,granted_memory_kb,used_memory_kb,,
grantee_count,waiter_count,timeout_error_count
from sys.dm_exec_query_resource_semaphores

SqlServer 内存篇(五)—— 常见内存错误与解决方法_Server_06

  • 检查sys.dm_exec_query_memory_grants视图,返回已经获得和仍在等待内存授予的查询的信息。

无需等待就获得内存授予的查询不会出现在此视图中,对于没有内存压力的sqlserver,这个视图应该为空。

select getdate() as runtime,
session_id,scheduler_id,DOP,request_time,grant_time,
request_memory_kb,granted_memory_kb,used_memory_kb,
timeout_sec,query_cost,resource_semaphore_id,waiter_order,is_next_candidate,wait_time_ms,
replace(replace(cast(s2.text as varchar(4000)),char(10),' '),char(13),' ') as sql_text
from sys.dm_exec_query_memory_grants
cross apply sys.dm_exec_sql_text(sql_handle) as s2

SqlServer 内存篇(五)—— 常见内存错误与解决方法_Server_07

 

三、 17189报错

当multi-page空间不足时,sqlserver可能无法在需要时创建新线程,此时新连接无法连上,但已连上的还能正常工作。

错误日志报错如下:

Logon Error: 17189, Severity: 16, State: 1.
Logon SQL Server failed with error code 0xc0000000 to spawn a thread to process a new login or connection. Check the SQL Server error log and the Windows event logs for information about possible related problems. [CLIENT: 172.21.123.48]

 

可能原因如下:

  • 当前线程数确实到达了sqlserver线程上限(不常见)

运行下面sql,检查有多少kpid<>0的spid,kpid<>0代表它当前使用线程运行,再加上sqlserver自己运行所需线程(10到20个),基本就是sqlserver当前使用的线程数

select count(*) from sys.processes where kpid<>0
  • multi-page内存有压力, multi-page内存压力分析部分