由于cursor leak导致的SQL Server内存问题

来源:这里教程网 时间:2026-03-02 10:02:30 作者:

SQL Server 2000开始,如果SQL Server遇到了内存不足的问题,我们会在SQL Server的error log中看到相关的信息和对当前memory分配和使用情况的打印信息.

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

[@more@]

当前这个例子中,遇到问题的SQL Server是32bit的SQL Server 2000.

Commited=960000 Target=960000 这里commited的和target都是960000个page,我们知道SQL Server的memory里面,一个page是8K。所以当前的buffer pool是7500MB。一个32bit的SQL Server 2000使用了7500MB内存,那么肯定是打开了AWE选项。commited表示当前已经使用的内存部分。

对于一个32bit的SQL Server来说,即使我们使用了AWE选项来扩展内存,依然还是有内存限制的。AWE扩展的部分,只能给data cache部分使用。即:用来存放table和index的数据页。

我们知道,一个数据库的内存部分,除了data 的cache之外,还有execution plan,statement,security context,lock ,cursor,optimizer,connection以及一些DLL和provider的内容。那么在32bit的SQL Server下,以上这些部分依然收到2GB内存的限制。

这就是说,即使我们给一个32bit的SQLServer无限制的增加内存,它还是可能遇到memory 不足的情况。

在这里,我们看到Hashed=768919,这个hashed部分指的就是data 和index的cache,这些数据使用hash链表的方式存放的。

接下来我们查看这个部分:

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

这个stolen的部分,可以理解为不在AWE扩展中的内存,也就是需要受到2GB限制的内存部分。这里总得stolen的内存在1500MB左右。其中绝大部分被Query Plan消耗了。

Query Plan指的是存放SQL 语句的plan的缓存部分。为什么语句的plan会占用如此多的内存呢?

1.客户有非常多的ad-hoc的语句。导致不能重用已经的plan而要不断的生成新的plan。或者由于某些原因,导致本可以重用plan的语句没有办法重用plan,必须生成新的。

2.这些plan没有办法从内存中清除掉。

通过以下命令可以验证我们的猜测:

Dbcc memorystatus --显示目前SQL server的内存使用和分配状况

Dbcc freeproccache --用来手动清除内存里面的plan cache

Dbcc memorystatus

DBCC ACTIVECURSORS --用来显示当前有多少没有关闭的游标

在这个系统中,我们发现执行完”Dbcc freeproccache“之后SQL plan cache的部分没有减少。这个说明这些plan都是正在使用中的active状态。这种情况下,通常是因为应用程序中有很多没有关闭的游标。

果然,”DBCC ACTIVECURSORS“返回了1万多行。

至此,我们可以得出结论,由于应用程序中的cursor leak,导致很多open的cursor在数据库端,这些open的cursor所引用的sql plan是不能被清除也不能被重用的,这个就是memory问题的原因了。

如果应用程序是使用的JDBC的driver,SQL Server 2000 JDBC SP3 修正了一些由于provider本身导致的cursor leak。但是本文中遇到的问题确是由于应用程序本身没有关闭cursor导致的。所以在处理server side cursor还是要格外小心。

相关推荐