SQL Server 内存泄露(memory leak)——游标导致的内存问题
原文:SQL Server 内存泄露(memory leak)——游标导致的内存问题
转自:http://blogs.msdn.com/b/apgcdsd/archive/2011/07/01/sql-server-memory-leak.aspx
问题描述:客户反映SQL Server运行一段时间就会报出内存不足的错误,怀疑是有内存泄露。从SQL Server的error log里面看如下错误信息:
2009-05-14 10:54:20.71 server Error: 17803, Severity: 20, State: 17
2009-05-14 10:54:20.71 server Insufficient memory available..
对于这种内存错误首先我们应该检查当前SQL Server的内存配置:
1. 32位的SQL Server还是64位的SQL Server?
2. 如果是32位的SQL Server,有没有启用AWE的选项。
3. 是否有设置最大服务器内存?
讲解这个问题之前需要先介绍一下32位和64位SQL Server在内存使用上的不同:
32位的应用程序在32位系统上的内存寻址空间是2GB的。我们可以使用AWE的方式使SQL Server使用超过2GB的物理内存,但是,寻址空间依然是2GB。
通过AWE扩展出来的内存,只可以用来作为数据缓冲区使用。除了数据缓存,SQL Server还需要使用内存来存储所有的执行计划,锁资源,用户连接信息,优化器使用作为评估语句执行计划的内存,语句执行内存等等。这些部分加起来不能超过2GB的内存。因此,即使我们为32位的SQL Server扩展了内存,一旦这2GB的内存不够提供给除了数据缓存的其他部分使用,SQL Server依然有面对内存不足的问题。本文中讨论的内存问题就是如此。
这里提供一篇文档,具体说明了如何为32位的SQL Server扩展内存:http://support.microsoft.com/default.aspx?scid=kb;en-us;274750
一旦我们使用了AWE选项为SQL Server扩展内存,我们一定要在sp_configure里面设置max server memory,以保证OS可以保留足够的物理内存。
我们回到这个内存的错误,检查系统的内存配置:该系统是32位的SQL Server 2000,启用了AWE选项,最大服务器内存设置为7500MB。这样我们有个初步的推断,问题可能是由于2GB限制以下的某个部分内存使用过多导致的。
接下来我们介绍另一个很重要的命令,这个命令在我们处理内存问题时经常会使用:
DBCC memorystatus
这个命令是用来输出当前SQL Server的内存使用情况的。在SQL Server 2005以后,我们引入了一个新的DMV,其中包含了更详细的内存分配信息:sys.dm_os_memory_clerks
在这个问题中,由于系统是SQL Server 2000,所以我们使用dbcc memorystatus来查看SQL Server的内存情况。这里有两篇文章分别介绍了SQL 2000和SQL 2005中如何查看dbcc memorystatus的结果:
http://support.microsoft.com/default.aspx?scid=kb;en-us;271624
http://support.microsoft.com/default.aspx?scid=kb;en-us;907877
我们进一步检查SQL Server 的error log:
2009-05-06 16:20:22.38 spid215 BPool::Map: no remappable address found.
2009-05-06 16:20:22.46 spid241 BPool::Map: no remappable address found.
2009-05-06 16:20:22.50 spid8 BPool::Map: no remappable address found.
2009-05-06 16:20:22.52 spid242 Buffer Distribution: Stolen=190614 Free=196 Procedures=271
Inram=0 Dirty=104759 Kept=0
I/O=0, Latched=35, Other=664125
2009-05-06 16:20:22.52 spid242 Buffer Counts: Commited=960000 Target=960000 Hashed=768919
InternalReservation=529 ExternalReservation=1426 Min Free=256 Visible= 191224
2009-05-06 16:20:22.52 spid242 Procedure Cache: TotalProcs=67 TotalPages=271 InUsePages=197
2009-05-06 16:20:22.52 spid242 Dynamic Memory Manager: Stolen=190767 OS Reserved=2584
OS Committed=2542
OS In Use=2538
Query Plan=156155 Optimizer=0
General=15253
Utilities=401 Connection=4046
2009-05-06 16:20:22.52 spid242 Global Memory Objects: Resource=9815 Locks=16467
SQLCache=76 Replication=2
LockBytes=2 ServerGlobal=28
Xact=5011
2009-05-06 16:20:22.52 spid242 Query Memory Manager: Grants=11 Waiting=15 Maximum=1512 Available=0
这里的输出结果就是DBCC memorystatus的一部分。Buffer Counts: Commited=960000 Target=960000 在这里的commited的值,是当前buffer pool的大小,target的值是计算出来的buffer pool的大小。如果target的值大于commited的值,说明buffer还要继续增长,反之,则是buffer pool要收缩。Hashed=768919这个是数据缓存的大小,即AWE扩展出来的这个部分。我们可以简单的计算一下,960000*8k,刚好就是7500MB。其中数据缓存是6000MB左右。剩下的部分总共使用了1500MB。
接下来查看Dynamic memory manager的部分:
Stolen. 是buffer pool中如下5个部分的总和(General, Query Plan, Optimizer, Utilities, Connection). 这个部分的内存分配页面都是小于8KB的。这里的stole的总和是190767,基本上等于960000-768919的差值。 这说明buffer pool中除去数据缓存的部分,剩下的内存就都是这5个部分���用了。
在stolen的部分中,我们看到Queryplan 的值非常高,156155*8k=1219MB。Plan cache是用来缓存语句的执行计划的。在32位SQL Server有2GB的内存地址的限制情况下,单独的plan cache使用到了大于1200MB是非常惊人的了,这也是我们这个内存问题的根本原因。
接下来我们要研究为什么这个系统的plan cache会增长到1.2GB。通常情况下,SQL Server会定期的去清除长时间未使用的语句缓存,保证plan cache的部分不会涨得过大。我们同样也提供一个命令去手动的清除plan cache的内存:dbcc freeproccache
这个命令执行完以后,会将当前没有正在被语句使用的缓存的执行计划从SQL Server的内存中全部清除。我们在SQL Server上执行dbcc freeproccache命令后,再次使用dbcc memorystatus来检查queryplan的部分。在这套系统中,我们发现dbcc freeproccache并没有成功清除掉Queryplan的部分,这个部分依然显示超过1200MB。这就是为什么SQL Server也同样不同清除Queryplan,而导致Queryplan涨到超过1200MB的原因了。
前面我们讲过,dbcc freeproccache可以强制清除那些没有被语句正在使用的执行计划。如果不能清除,说明这些执行计划都在被使用中。那么什么情况会导致所有的执行计划都在被使用中呢?我们联想到问题的描述是这个内存的时候是慢慢增长上来的,那么这个情况就很有可能是应用程序中遗留了游标没有关闭。
检查系统中的活动游标,我们引入了另一个命令:DBCC ACTIVECURSORS 这个命令会将当前系统所有未关闭的游标打印出来:
SPID Cursor Id Pages Stmt
--------------- ------------------------------------------------------------------
55 180150581 2 select * from MESSAGE_DATA where MSG_NUMBER = @P1
55 180150580 2 select mhead.msg_number,customer_id,originator,status,queue,
55 180150577 4 select macc.delivery_time,macc.msg_number,macc.recipient_num
55 180150576 3 select mhis.msg_number,mhis.recipient_number,mhis.update_tim
55 180150568 4 select mh.originator,mh.datatype_id,mh.creation_time,mh.reci
55 180150547 8 select mh.msg_number,mh.orig_msg_number,mh.child_msg_number,
55 180150460 8 select customer_id, company, contact_name, contact_phone, ma
62 180150847 10 select pii.msg_number, pii.item_number, pii.type, pii.amount
62 180150710 10 select pii.msg_number, pii.item_number, pii.type, pii.amount
62 180150661 10 select pii.msg_number, pii.item_number, pii.type, pii.amount
…….
这里输出了总共9600多个活动游标,并且同时输出了游标使用的语句。
到目前为止,问题就很清楚了。使用JDBC的应用程序遗漏了某些游标没有关系,因此导致这些游标使用的语句的执行计划一直无法被SQL Server清除。因此导致了QueryPlan占用了大量的内存,数据库报出内存不足的错误。
SQL Server 内存泄露(memory leak)——游标导致的内存问题的更多相关文章
- 内存溢出(Oom)和内存泄露(Memory leak)
1.概念 内存溢出(Oom):1.内存不够用:2.数据长度短的数据类型存储了一个数据长度较大的数据类型:3.一个结果 内存泄露(Memory leak):1.忘记释放已用内存,内存管理较为常见的现象: ...
- 内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别
内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数 ...
- python内存泄露memory leak排查记录
问题描述 A服务,是一个检测MGR集群主节点是否发生变化的服务,使用python语言实现的. 针对每个集群,主线程会创建一个子线程,并由子线程去检测.子线程会频繁的创建和销毁. 上线以后,由于经常会有 ...
- 利用linux的mtrace命令定位内存泄露(Memory Leak)
一谈到内存泄露, 多数程序猿都闻之色变. 没错, 内存泄露非常easy引入. 但非常难定位. 以你我的手机为例(如果不常常关机). 如果每天泄露一些内存, 那么開始的一个星期, 你会发现手机好好的. ...
- 使用JProfiler分析定位java内存泄露memory leak
使用jprofiler远程profile JBoss应用服务器 项目中发现JBoss出现内存泄露, 从2G一直涨到3.5G左右 开始考虑使用jmap dump出内存来, 在用jhap打开浏览器分析. ...
- Java 基础 - 内存泄露Memory leak & 内存溢出Out of memory
内存泄露 & 内存溢出 关系 https://www.cnblogs.com/panxuejun/p/5883044.html 内存泄露的6种情况: https://blog.csdn.net ...
- 内存泄露 memory leak 的原因
#include <iostream> using namespace std; void foo() { MyClass *x; x = new MyClass(); //指向的丢失了 ...
- Android 内存管理 &Memory Leak & OOM 分析
转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...
- 内存泄漏(Memory Leak)
什么情况下会导致内存泄露(Memory Leak)? Android 的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M.因此我们所能利用 的内存空间是有限的.如果我们的 ...
随机推荐
- python版本wifi共享工具
原先不知道win7系统也可以当作无线路由器,既然知道了这个东西那么就搞搞了 使用python写的一个wifi共享工具,还不够完善,有些功能还没做(说明:internet共享连接需要手动设置)..... ...
- jconsole线程面板中的阻塞总数和等待总数(转)
阻塞总数 Blocked count is the total number of times that the thread blocked to enter or reenter a monito ...
- 你不知道的Eclipse的用法:使用MAT分析Android的内存
如果使用DDMS确实发现了我们程序中存在内存泄露,那如何定位到具体出现问题的代码片段,最终找到问题所在呢?如果从头到尾分析代码逻辑,那肯定会把人逼疯,特别是在维护别人写的代码的时候.这里介绍一个极好的 ...
- Visual Studio Code中配置GO开发环境
在Visual Studio Code中配置GO开发环境 一.GO语言安装 详情查看:GO语言下载.安装.配置 二.GoLang插件介绍 对于Visual Studio Code开发工具,有一款优秀的 ...
- Ubuntu Linux 永山(mount)分
在一般情况下,我们想安装一个分区解决方案是使用mount命令,因为我想/dev/sda3安装/media/aborn/data通过使用下面的命令 sudo mount /dev/sda3 /media ...
- 设备Oracle当误差:环境不符合要求》》解决方法
一旦安装Oracle当我常常会遇到这样的问题.也没太在意,改了一下client\stage\cvu文件夹cvu_prereq.xml档(添加支持目前的操作系统信息)为了克服,我没有做笔记,但后来有同学 ...
- uptime
linux uptime命令主要用于获取主机运行时间和查询linux系统负载等信息.uptime命令过去只显示系统运行多久.现在,可以显示系统已经运行了多长时间,信息显示依次为:现在时间.系统已经运行 ...
- UVA - 12232 Exclusive-OR (并查集扩展偏离向量)
Description You are not given n non-negative integersX0,X1,..., Xn-1 less than220, but they do exist ...
- http1.0 和 http1.1 区别
http1.0 和 http1.1 主要区别 1.背景 KeepAlive是就是通常所称的长连接.KeepAlive带来的好处是可以减少tcp连接的开销,这对于短response body的请求效 ...
- flex4 一些项目使用的技术
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="ht ...