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)——游标导致的内存问题相关推荐
- 内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别
内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数 ...
- python内存泄露memory leak排查记录
问题描述 A服务,是一个检测MGR集群主节点是否发生变化的服务,使用python语言实现的. 针对每个集群,主线程会创建一个子线程,并由子线程去检测.子线程会频繁的创建和销毁. 上线以后,由于经常会有 ...
- 什么是内存溢出(Out Of Memory---OOM)和内存泄露 (Memory Leak)
1.内存溢出:(Out Of Memory---OOM) 系统已经不能再分配出你所需要的空间,比如系统现在只有1G的空间,但是你偏偏要2个G空间,这就叫内存溢出 例子:一个盘子用尽各种方法只能装4个果 ...
- 性能优化之内存泄露(Memory Leak)常用分析工具(另3种)
1 LeakCanary(最常用,能监控整个App内存泄漏情况) 1.1 使用LeakCanary // 仅在debug包启用LeakCanary debugImplementation 'com.s ...
- 利用linux的mtrace命令定位内存泄露(Memory Leak)
一谈到内存泄露, 多数程序员都闻之色变. 没错, 内存泄露很容易引入, 但很难定位. 以你我的手机为例(假设不经常关机), 如果每天泄露一些内存, 那么开始的一个星期, 你会发现手机好好的, 当内存 ...
- Android 内存管理 Memory Leak OOM 分析
转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...
- python 单例模式内存泄露_彻底搞懂Java内存泄露
之前一直在简书写作,第一次发布到SF上来,也是第一次使用SF,后面会尽量同步到SF,更多文章请关注: 简书 编程之乐 转载请注明出处:谢谢! Java内存回收方式 Java判断对象是否可以回收使用的而 ...
- [翻译] - Inside SQL Server 2000's Memory Management Facilities
原文地址:Inside SQL Server 2000's Memory Management Facilities 翻译:RicCC Ken Henderson Microsoft ...
- SQL Server中自定义函数和游标应用的经典案例
2019独角兽企业重金招聘Python工程师标准>>> SQL Server中自定义函数和游标应用的经典案例 转载于:https://my.oschina.net/zhddzr/bl ...
最新文章
- Ajax回退刷新页面问题的解决办法
- 时代中坚:互联网电视迎来极致时代
- 总线的集中式仲裁(讲述计时器定时查询方式,独立请求方式,链式查询方式的优缺点)
- 5年前我们摸爬滚打进入测试行业,如今你后悔吗?
- DIV块中 元素垂直居中
- 基于wireshark和NetAssist的单机模拟抓TCP包:三次握手、四次挥手、长连接
- 模拟退火算法介绍和实例实现
- ubuntu20.04安装搜狗输入法
- java.exe和javaw.exe有什么区别吗?
- linux数字版权管理,数字版权管理系统 DRM
- 数据整理—dplyr包(mutate系列)
- 元旦节快乐,新的一年新的福利,给大家准备了高清无码的白虎图
- 核磁谱图分析步骤_核磁一般氢谱和碳谱的解析步骤
- 《数据结构与算法实战-周强-2.2》——大炮打蚊子
- 瑞萨L4级自动驾驶方案---基于R-Car V3H SoC的自动驾驶
- 网站改版会影响网站流量吗
- Armadillo C++ Library
- 如何检查显卡支持哪个版本的CUDA ?
- 工作中常用的学习总结套路
- 21天打卡挑战学习MySQL—Day第一周 第一篇
热门文章
- dll注入的一种方式
- Elasticsearch--进阶-aggregations聚合分析_ES的强大的数据分析能力厉害啊---全文检索引擎ElasticSearch工作笔记016
- SpringCloud工作笔记089---SpringBoot中Mybatis使用Condition_Criteria如何筛选日期类型数据
- JAVA面试要点007---equals和==的区别小结
- Linux学习笔记020---CentOs7.3 搭建 Solr单机服务
- SpringCloud学习笔记013---Spring的@PostConstruct标签_初始化项目字典
- Grunt学习笔记002---Gruntfile.js详解
- C#.NET验证码智能识别学习笔记---03#.Net中@符号的意思
- 两者结合在一起看SphereFace
- basler 相机使用出现的问题