使用SQL Server 2005 或者2000的朋友可能会经常碰到,内存占用的问题,SQL总是能将所有内存消耗殆尽,这时候我们会怀疑我们的程序是否没有释放资源,或者断开连接,也可能怀疑SQL存在一个大BUG,我也碰到了这个问题,再查了很多资料后有了这样的发现:
以下是微软官网的解释:
在您启动 SQL Server 之后,SQL Server 内存使用量将会持续稳定上升,即使当服务器上活动很少时也不会下降。另外,任务管理器和性能监视器将显示计算机上可用的物理内存稳定下降,直到可用内存降到 4 至 10 MB 为止。
仅仅出现这种状态并不表示内存泄漏。此状态是正常的,并且是 SQL Server 缓冲池的预期状态。
默认情况下,SQL Server 根据操作系统报告的物理内存加载来动态增大和收缩其缓冲池(缓存)的大小。只要有足够的内存可用于防止分页(在 4 至 10 MB 之间),SQL Server 缓冲池就会继续增大。像在与 SQL Server 分配内存位于相同计算机上的其他进程一样,SQL Server 缓冲区管理器将在需要的时候释放内存。SQL Server 每秒可以释放和获取几兆字节的内存,从而使它可以快速适应内存分配更改。
您可以使用最小服务器内存和最大服务器内存配置选项来设置 SQL Server 数据库引擎使用的内存(缓冲池)量的上下限。在设置最小服务器内存和最大服务器内存选项之前,请查阅以下 Microsoft 知识库文章中标题为“内存”一节中的参考信息:
注意,最大服务器内存选项只限制 SQL Server 缓冲池的大小。最大服务器内存选项不限制其余未保留内存区域,SQL Server 准备将该区域分配给其他组件(例如扩展存储过程、COM 对象以及非共享 DLL、EXE 和 MAPI 组件)。由于存在上述分配过程,因此 SQL Server 专用字节超过最大服务器内存配置是正常的。
原文地址:http://support.microsoft.com/default.aspx?scid=kb;zh-cn;321363
还有个比较官方的解释但是不知道来源:
动态管理 Windows NT 和 Windows 2000 上的内存
当 SQL Server 数据库引擎在 Microsoft® Windows NT® 或 Windows® 2000 上运行时,其默认内存管理行为并不是获取特定的内存量,而是在不产生多余换页 I/O 的情况下获取尽可能多的内存。为此,数据库引擎获取尽可能多的可用内存,同时保留足够的可用内存以防操作系统交换内存。
SQL Server 实例在启动时通常获取 8 到 12 MB 的内存以完成初始化过程。当实例完成初始化后,就不会再获取更多的内存,直到用户连接到该实例并开始产生工作负荷。这时,该实例根据需要不停地获取内存以支持工作负荷。随着更多的用户连接并运行查询,SQL Server 将获取支持需求所需的额外内存。该实例将继续获取内存直到达到自身的内存分配目标,并且直到达到该目标的下限才会释放任何内存。
为了在不产生多余换页 I/O 的情况下获取尽可能多的内存,SQL Server 的每个实例都设置一个内存获取目标,直到计算机的可用物理内存在 4 MB 到 10 MB 的范围内。之所以选择该范围是因为测试表明 Windows NT 和 Windows 2000 都有最小内存交换,直到内存分配等于可用物理内存减去 4 MB。工作负荷处理任务重的 SQL Server 实例保留的可用物理内存为范围的较低端 (4 MB);工作负荷处理任务轻的实例保留的可用物理内存为范围的较高端 (10 MB)。
SQL Server 实例的目标随工作负荷的改变而变化。当更多的用户连接并产生更多的工作时,该实例倾向于获取更多的内存以使可用的内存保持在 4 MB 的限制以下。当工作负荷减轻时,该实例将其目标调整为 10 MB 的可用空间,并释放内存给操作系统。将可用空间量保持在 10 MB 与 4 MB 之间可防止 Windows NT 或 Windows 2000 过多执行换页操作,同时使 SQL Server 得以获得尽可能最大的高速缓冲存储器而不至引起额外的交换。
实例的目标内存设置与数据库缓冲池的页相对于可用池大小的需求有关。在任何即时点,缓冲区页的总需求取决于满足所有当前执行的查询所需的数据页数。如果相对于高速缓冲存储器内的页数,数据页的需求很大,则当前在缓冲区内的每一页很可能在相对较短的时间内由新页替换。这可由"缓冲区管理器"对象的"页生命期"性能计数器来度量。对于相对较小的缓冲区有较高需求的情况将生成短生命期,而纯粹的影响就是使 I/O 增加,因为在页可由多个逻辑读取引用之前往往要被重写。为减轻这个问题,数据库引擎可以获取更多的内存以增加高速缓冲存储器的大小。当页生命期长时,数据库引擎将可用内存定位于目标的高端 (10 MB);而当页生命期短时,数据库引擎定位于目标范围的低端 (4 MB)。
随着其它应用程序在运行 SQL Server 实例的计算机上启动,它们消耗内存致使可用物理内存量降到 SQL Server 的目标以下。SQL Server 实例于是从其地址空间释放足够内存,以使可用内存量回到 SQL Server 的目标。如果有其它应用程序停止运行而使可用内存增多,SQL Server 实例将增加其内存分配大小。SQL Server 可以每秒释放并获取几 MB 字节的内存,这使它得以根据内存分配变化作出快速调整。
上面说的意思都差不多,就是SQL会为一直为程序分配新的内存直到你的内存接近耗尽(4-10M)或者达到你设置的内存最大值(SQL Server 2005 默认的最大值为2147483647M)试想,如果这样设置,那SQL当然要一直吃掉内存,可是有写地方也提到不将这个值修改,也就是要将SQL服务器单独放在一台机器上,那么这台机器将会只保留4-10M的内存用来位置基本程序运行,其他内存均用来处理SQL服务,这样做是ByDesign的。可以减少重复数据对SQL服务器的请求,让他们直接访问内存中的数据。
不知道上面说的是否清楚,下面有个比较白话的解释内存为何长期处于高占用状态:
最近在做一个电信的MIS系统,由于数据库的数据量庞大(最少也有500万),发现了一个sql server 长时间占有内存的现象。
当你查询数据的数据量比较大时,sqlserver会把查询结果缓存在内存中,保证你下次查询同样的记录时会很快得到结果,所以内存使用量会激增。
在你完成此次查询后,sqlserver不会马上释放内存,数据会仍然放在内存中,这是sqlserver的优化策略,sqlserver会不断地占用你的系统内存,来加快sqlserver的运行速度,当你的系统中的其它服务也需要内存时,它才会自动释放部分内存。一句话,sqlserver不会让你的系统有闲置的内存,除非你设置sqlserver的最大内存使用量。这样也没什么不好,如果你的系统很大,单独给sqlserver一台机器,这样会提高它的性能,再有就是增加SQL Server服务器的内存。
如果你只是开发用,要想让sqlserver释放内存,重启sqlserver的服务就行了。如果不想让sqlserver占用太多内存,设置sqlserver的最大内存占用量.
看了这么多,至于解决方案,不外乎重启服务和使用第三方工具释放内存,后者效果不错,但还是没有找到本身是否能够尽快释放内存,这还要靠大家努力,也许你知道希望能留言告诉我,与大家分享。