原文: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)——游标导致的内存问题的更多相关文章

  1. 内存溢出(Oom)和内存泄露(Memory leak)

    1.概念 内存溢出(Oom):1.内存不够用:2.数据长度短的数据类型存储了一个数据长度较大的数据类型:3.一个结果 内存泄露(Memory leak):1.忘记释放已用内存,内存管理较为常见的现象: ...

  2. 内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别

    内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数 ...

  3. python内存泄露memory leak排查记录

    问题描述 A服务,是一个检测MGR集群主节点是否发生变化的服务,使用python语言实现的. 针对每个集群,主线程会创建一个子线程,并由子线程去检测.子线程会频繁的创建和销毁. 上线以后,由于经常会有 ...

  4. 利用linux的mtrace命令定位内存泄露(Memory Leak)

    一谈到内存泄露, 多数程序猿都闻之色变. 没错, 内存泄露非常easy引入. 但非常难定位.  以你我的手机为例(如果不常常关机). 如果每天泄露一些内存, 那么開始的一个星期, 你会发现手机好好的. ...

  5. 使用JProfiler分析定位java内存泄露memory leak

    使用jprofiler远程profile JBoss应用服务器 项目中发现JBoss出现内存泄露, 从2G一直涨到3.5G左右 开始考虑使用jmap dump出内存来, 在用jhap打开浏览器分析. ...

  6. Java 基础 - 内存泄露Memory leak & 内存溢出Out of memory

    内存泄露 & 内存溢出 关系 https://www.cnblogs.com/panxuejun/p/5883044.html 内存泄露的6种情况: https://blog.csdn.net ...

  7. 内存泄露 memory leak 的原因

    #include <iostream> using namespace std; void foo() { MyClass *x; x = new MyClass(); //指向的丢失了 ...

  8. Android 内存管理 &Memory Leak & OOM 分析

    转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...

  9. 内存泄漏(Memory Leak)

    什么情况下会导致内存泄露(Memory Leak)? Android 的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M.因此我们所能利用 的内存空间是有限的.如果我们的 ...

随机推荐

  1. freemarker导出word带图片

    导出word带图片 如果你需要在word中添加图片,那你就在第一步制作模板时,加入一张图片占位,然后打开xml文档,可以看到如下的一片base64编码后的代码: <w:binData w:nam ...

  2. 2012天津E题

    给我们n个坐标点和一个距离d,表示车开m米就没油了. 然后要选几个点建立油站,使得能够从1出发遍历所有的点,然后回到1.  并且规定1这个点必须有油站,在第i个点建立油站的费用是 2^(i-1) 因为 ...

  3. 使用psftp.exe

    使用psftp.exe 点击打开psftp.exe,出现如下图的命令窗口.  

  4. HttpDNS 服务详解(转)

    但凡使用域名来给用户提供服务的互联网企业,都或多或少地无法避免在有中国特色的互联网环境中遭遇到各种域名被缓存.用户跨网访问缓慢等问题.那么对于腾讯这样的域名数量在10万级别的互联网公司来讲,域名解析异 ...

  5. Java EE (9) -- JDBC & JTA

    Connection接口中定义了5中隔离级别常量 Connection.TRANSACTION_NONE  --  不支持事务 Connection.TRANSACTION_READ_UNCOMMIT ...

  6. SQL声明发育异常导致项目错误

    1.错误叙述性说明 严重:Exception occurred during processing request:Statement Callback;SQL[   ];OALL8处于不一致状态; ...

  7. Visual Studio Tips: How to change project namespace

    /* Author: Jiangong SUN */ If you want to modify a project's namespace and its physical container na ...

  8. android studio下gradle与Git错误解决方法

    Error: Gradle: Execution failed for task ':mytask' > A problem occurred starting process 'command ...

  9. 小米2S Mk6.0.1 [只能做测试体验,不能使用]

    上几张高清图片.. 说明: 此版本只能做测试体验,不能做实际使用. 开发者: laser杨万荣 感谢: 秋叶随风ivan, m1cha 及 MoKee Open Source的各位开发者 下载地址:链 ...

  10. Java Map 迭代

    Map迭代 有两种 道路 遍历 Map该方法:      1  Set<K> KeySet(): 获取全部的键,得到set集合,迭代, 通过get( key)获取值!      2  Se ...