huahit

常用链接

统计

积分与排名

有用的编程连接

最新评论

内存管理机制

深入SQL SERVER 2000的内存管理机制

Ken Henderson

Microsoft Corporation

备注:Ken Henderson 从开发者的角度来阐述了SQL SERVER 2000内存管理的内部机制

简介

在本专栏中,我们将从一个开发者的角度来探索SQL SERVER 的内存管理。因此我们将讨论服务器内存管理的API和操作系统的内存管理机制,他们是如何运行的? 以这种新颖的方式来探讨SQL SERVER内存管理,可以使开发人员明白其中的前因后果,精通一个产品,我们要了解它内部是如何运行和特定的用途。

我们首先开始的研究,它包括一些Windows内存管理的基本原理。和所有的32位的Windows程序一样,SQL SERVER也是使用Windows的内存管理机制来分配、释放和通用的内存管理资源。也就是说,SQLSERVER和其他Windows程序一样通过WIN32 API函数和操作系统提供的内存管理资源交互。

因为几乎所有的SQLSERVER内存分配都是使用虚拟内存(而不是堆的方式),大部分的内存分配的代码分解到最后都是调有Win32的VirtualAlloVirtualFree API函数。SQL SERVER通过调用VirtualAllo函数来预留和提交虚拟内存,通过VirtualFree函数来释放内存。

虚拟内存和物理内存

X86处理器的系列中,Windows提供所有的程序可以寻址4GB虚拟内存空间。所谓“虚拟”的意思是,这并不是传统意义上的内存,它仅仅是一段没有物理存储的隐式地址段。因为只有一个程序开始内存分配,才开始使用这些地址段和物理的分配存储空间。而且,这些物理的存储空间并不需要物理的内存(不完全),通常是磁盘空间。明确的说应该是在系统的虚拟页文件中。这就是为什么有许多程序(每个程序有4GB的虚拟内存空间)可以同时运行在只有128M的物理内存的机器上,就像每个程序自己分配真实的内存一样。Windows透明地控制从系统页文件拷贝和读取数据,因此程序可以在运行的机器上分配比物理内存更多的内存空间并且各种程序可以均等的访问该机器物理内存。

4GB的内存地址空间分为2块:用户内存空间和核心内存空间。默认每个容量为2G,你可以通过Windows NT 系列操作系统的BOOT.INI文件来改变默认空间的大小(比如:Windows NT,Windows 2000,Windows XP 和Windows Server 2003都是Windows NT 系列的产品,Windows 9x 和 Windows ME不是的)。

Figure 1. Windows partitions a process's virtual address space into the user mode (application) and kernel mode (operating system) partitions.

尽管每一个程序接受自己的虚拟内存空间,系统代码和设备驱动代码共享一个单独私有的虚拟地址空间。每个虚拟内存页都和一种特殊处理器模式关联。为了满足所有的系统页都可以被访问,处理器必须是请求模式。这个意思是说用户的程序是无法直接访问核心内存空间,系统必须切换为核心模式,这样核心模式的内存空间才可以被访问。

程序内存空间调整

在BOOT.INI文件中有一个/3GB的参数可以允许改变默认的限制(这个参数在Windows advanced server和 Windows 2000 Data Center有效),这样可以通过牺牲核心内存空间(从2G降低到1G)将用户应用程序的内存空间从2G增加到3G.在Windows的用法中,这种机制叫程序内存空间调整或叫4GT调整(4GT).你可以通过在BOOT.INI文件的[operating systems]区域的适当的行加/3GB参数来调整应用程序的内存空间.对一般的人来说可以选择配置BOOT.INI文件的[operating systems]区域的适当的行增加/3GB或不加/3GB参数来启动系统.

警告:你也可以在Windows 2000 Professional和Windows 2000 的启动文件中加/3GB的参数来启动系统,可是这样只是减少了核心内存空间到1GB但并没有增加应用程序内存空间.换句话说,这样做并没有从降低核心内存空间获得益处

注释:在WindowsXP和Windows Server 2003中提供一个新的启动参数/USERVA,可以和/3GB参数一样使用,但允许你有更加出色的控制度.你可以象/3GB 一样将/USERVA参数到BOOT.INI文件中. /USERVA参数比/3GB的优势在于,它可以允许你指定内存地址空间分配给应用程序的大小.比如: /USERVA=2500 的意思就是配置2.5G的内存地址空间预留给用户内存空间,1.5G的留给核心内存空间.特别说明/3GB参数还是可以单独使用的

...:::小鸟巢:::...
小鸟--永远的好奇,不断的求知者
小鸟巢--小鸟聚集的地方
小鸟们的天堂,求知者的乐园
我们为您提供各种各样的资料
http://xnc.cn
http://lbns.org
ip地址已设置保密
2005-11-4 21:59:00
cmsea
帅哥哟,在线,有人找我吗?
天秤座10-12
ㄚっ小鸟っㄚ
帝国元帅
88888888
5446
46808
无门无派
2003年10月11日
2
 用支付宝给cmsea付款或购买其商品,支付宝交易免手续费、安全、快捷!QQ 点击这里发送电子邮件给cmsea访问cmsea的主页

发贴心情

可访问大地址的应用 (Large-Address-Aware Executables)

在Windows增加支持/3GB参数以前,一个应用程序是无法访问一个带有高位设置的指针.一个32位的指针只有前31位地址空间可以被用户模式的应用程序访问.这剩余的一位不用.因此有一些聪明的开发者因为其他的目的不愿意在处理内存地址空间时浪费这一位.(举例来说:可以用来标志一个指针引用其它应用程序分配的数据类型).这样就/3GB参数就遇到一个难题,因为这种类型的程序不能方便的区分一个合法的指针引用的内存空间在2G的分界线以上与一个内存地址空间在2G以下,但它的高位已经被用做它用的指针.基本上如果一台机器用/3GB的参数启动,这种应用程序是无法运行的.为解决这种状况,微软在WIN32的PE文件Characteristics字段增加了一个新的标志位来表示一个程序是否运行在可访问大地址的(Large-Address-Aware Executables)模式.当该标志位被起用( IMAGE_FILE_LARGE_ADDRESS_AWARE ),该可执行文件头部Characteristics字段的32位被置位.通过这个可执行文件头部的标志位,应用程序可以暗示WINDOWS 它可以处理带有高位设置的指针,这样就不会带来任何异常结果.当该标志被置位并且支持这种方式启动的Windows也是通过/3GB的参数启动,这时操作系统会提供一直扩展的私有用户模式的地址空间给应用程序.你可以通过工具,比如: DumpBin 和 ImageCfg (转储可执行文件的头部)来检查一个可执行文件的该标志位.Visual C++ 通过 /LARGEADDRESSAWARE 连接器开关来表示IMAGE_FILE_LARGE_ADDRESS_AWARE,SQL SERVR已经将该标志位激活,所以你可以在支持/3GB参数的Windows 版本中使用该参数,这样操作系统回自动扩展SQL SERVER的用户内存空间.

注释:Windows在可执行文件启动时检查IMAGE_FILE_LARGE_ADDRESS_AWARE 标志位,但忽略DLL文件.DLL代码必须自动处理高位被置位的指针。

物理内存扩展

Intel 处理器自从Pentium PRO开始,以后的处理器都支持一种物理内存扩展(PAE)的内存映射模式。PAE模式提供了可以访问64GB的物理内存空间。在PAE模式中,内存管理单元(Memory Management Unit (MMU))仍然执行:页目录入口page directory entries(PDEs) 和页表入口page table entries (PTEs),但是在此之上有一个新的级别:页目录指针表。同时,在PAE模式PDEs 和PTEs是64位的(不仅仅是标准的32位),这样系统可以映射比标准转换更多的内存空间,因为PDEs 和PTEs模式的寻址宽度是标准的2倍。这并不仅仅是增加了页目录指针表。页目录指针表被用来管理这些大容量表和索引。一些特殊版本的Windows内核需要运行在PAE模式。这中内核集成在Windows 2000以及以后的版本中,在单处理器的机器中体现在Ntkrnlpa.exe文件中,在多处理器的机器中体现在Ntkrnlpamp.exe文件中。你可以向增加/3GB和/USERVA参数一样在BOOT.INI文件中加/PAE参数激活PAE模式。

地址窗口扩展

Windows的地址窗口扩展(AWE)机制可以允许应用程序访问超过4GB的物理内存。一个32位的指针是一个整数,只能保存0x00000000到0xFFFFFFFF的值,就是说可以引用4GB 以内线性的内存地址空间,AWE允许一个应用程序绕过这些限制,通过操作系统访问所有的内存空间。

从概念上说,AWE并不是一个新的事物。在计算机发展之初,操作系统和应用程序已经使用相似的机制回避指针的限制。例如:我们倒退到DOS年代,32位扩充功能被经常用来允许一个16位的程序访问他自已以外的内存地址空间。一些特殊目的管理者和API经常使用扩充内存和扩展内存。你可能记得这样一个很久以前产品Quarterdeck QEMM-386经常用来做这样的事情。典型的机制是允许一个指针可以访问超过本身限制的空间,(比如:地址太大无法在自己的指针中)通过在可以访问的地址空间分配一个窗口或区域来和本身无法访问的内存地址之间传递指针。AWE的工作原理:你可以在可以访问的地址空间提供一块区域(窗口)作为分段传输区,来传送在用户内存空间无法访问的内存地址。

为了使用AWE,一个应用程序需要:

1.分配的物理内存地址可以通过AllocateUserPhysicalPages API函数访问。这个函数需要调用者有Lock Pages in Memory的权限。

2.在可以访问的内存空间建立一块区域。通过VirtualAlloc API函数可以作为映射一个物理内存的映射窗口。

3.通过MapUserPhysicalPages 或MapUserPhysicalPagesScatter WIN32 API 函数完成物理内存和虚拟内存的映射。

AWE已经存在于所有的Windows 2000和以后的操作系统中,甚至可以用于物理内存低于2GB的操作系统中,最典型的应用是在2GB或以上物理内存的机器上,因为这是一个32位处理器访问3GB以下内存空间的唯一方法。如果你在一个低于3GB物理内存的SQL Server系统中激活AWE支持,系统将忽略这个选项同时转换为虚拟内存管理器代替。AWE内存有一个有趣的特征就是从不和磁盘交换数据。你也许注意到特有的AWE API程序引用可以访问的内存空间是作为物理内存访问。这点确切的说就是:AWE内存是不和系统的虚拟页面文件交互物理内存空间。

虚拟内存窗口被用来缓存AWE读写访问物理内存的请求。因此,当你配置这个窗口是PAGE_READWRITE唯一可以保护的特征就是转嫁给了VirtualAlloc API函数。不要惊奇,这也意味你不能用VirtualProtect API函数来保护这块内存区域的修改和访问。

注释:还没有专门的工具用来调查应用程序AWE内存使用(任务管理器,性能监视器和监视系统 等等),显示每一个程序AWE内存的使用数量。这样就没有每个程序使用AWE内存数量的轨迹,同时这些内存也没包括在每个的程序的工作内存集中。

/3GB 和AWE比较

增加用户程序地址空间的能力几乎有50%的应用程序是通过内存调整,这是在Windows内存管理机制当中非常快捷和受欢迎的手段。而且Windows AWE内存机制也是非常灵活和稳定的。就像我前面所说的,当你增加1G的用户内存空间,这些内存是通过减少核心内存空间获得的(从2G减到1G)。因为核心代码的运行对整个内存空间来说是很狭窄的一块即使用于2G的空间,收缩这些内存空间意味着内部核心架构也会收缩。其中最重要的是windows用来管理物理内存的表,当你收缩核心内存空间到1G,你就限制了这个表的大小,这样只能管理最大16GB的物理内存。例如:如果你的应用程序运行在有64GB物理内存的SERVER上并且你在启动时加了/3GB的参数。你只能访问整个内存的25%的空间—其余的48GB的内存空间无论时操作系统还是应用程序都无法访问。AWE可以允许你访问比加/3GB参数更高的内存空间。显然,你通过/3GB的参数只是增加了1GB的用户内存空间,这些增加的内存空间只是对那些大地址自动获得的应用程序有效,但是只有1GB。和/3GB参数对比,AWE可以使整个的物理内存对操作系统有效和对使用AWE WIN32 API的应用程序有效。因此,AWE使用和操作起来更加复杂,也更加灵活和可扩展。

着并不是说/3GB比AWE更好是不存在的-不过这确实存在,比如:如果你需要分配更多的内存空间,但不能在AWE中分配(线程堆栈,内存锁,过程计划),你也许发现/3GB回更好一些。


...:::小鸟巢:::...
小鸟--永远的好奇,不断的求知者
小鸟巢--小鸟聚集的地方
小鸟们的天堂,求知者的乐园
我们为您提供各种各样的资料
http://xnc.cn
http://lbns.org
ip地址已设置保密
2005-11-4 22:00:00
cmsea
帅哥哟,在线,有人找我吗?
天秤座10-12
ㄚっ小鸟っㄚ
帝国元帅
88888888
5446
46808
无门无派
2003年10月11日
3
 用支付宝给cmsea付款或购买其商品,支付宝交易免手续费、安全、快捷!QQ 点击这里发送电子邮件给cmsea访问cmsea的主页

发贴心情

内存区域

SQL Server是分2块区域来组织内存分配,分别是Bpool (缓冲池区)和MemToLeave (内存释放区),如果你使用AWE内存,那么实际上有第三个区:Windows AWE支持的高于3GB的物理内存区。

缓冲池区是这3块内存区中最卓越的,是SQL SERVER最初分配的缓冲池供最初的数据页和索引页使用,并且被用来分配小于8K的内存。MemToLeave 是由虚拟内存空间组成包括在用户内存空间没有被缓冲池区使用的内存空间之中。Windows AWE调用3GB以上内存空间的函数作为缓冲池区的扩展可以提供额外的内存空间缓存数据页和索引页。

当你启动SQL SERVER时,缓冲池区的上限是根据机器中物理内存推算或用户内存空间的大小。一旦缓冲池区的大小被确定,内存释放区就紧随其后,不至于被后面的缓冲池区保留部分划分成分散的碎片。然后缓冲池区又在内存释放区旁边,使用32块单独的保留区运行DLL文件和其他在缓冲池区被预定时SQL SERVER中使用的虚拟内存空间。当缓冲池区被预留后,内存释放区被释放。这段区域被SQL SERVER内部用来扩展8K的数据页和分配给其他外部应用(就像:内存消费者是SQL SERVER主要引擎以外的SQL SERVER进程),比如:OLE DB providers,COM对象等等.

因此,当SQL SERVER已经启动, Bpool (缓冲池区)就被预留,但不提交,同时在该进程在虚拟内存空间内的MemToLeave (内存释放区)其实是空闲区域.如果你通过性能分析器的 Virtual Bytes Perform 计数器,在SQL Server启动后看SQL SERVER的进程,你会看到它可以反映Bpool (缓冲池区)预留区.我看到人们有些惊慌,因为这个数值比较高—毕竟,它反映的不是本机器的总共物理内存就是最大的用户内存空间减去MemToLeave (内存释放区).这是不用担心的,比较而言这只是保留区,没有提交的空间.就如我前面所述,保留空间只是地址空间—并没有真实的物理内存存储直到内存空间被提交. 随着时间的过去,内存空间被提交,Bpool (缓冲池区)将会增加,知道该SERVER原始启动时确定的上限.

监控SQL Server虚拟内存的使用

你可以通过 SQL Server:Buffer Manager\Target Pages Perform计数器跟踪Bpool (缓冲池区)确定的最大空间.因为SERVER不同的部分需要内存, Bpool (缓冲池区)提交8K大小的页(这是原始保留的直到提交的大小到达确定目标).你可以通过 SQL Server:Buffer Manager\Total Pages Perform计数器跟踪Bpool (缓冲池区)使用的提交虚拟内存, 你可以通过 Pivate Bytes计数器跟踪SQL Server进程使用的全部提交的虚拟内存.

因为, 大部分的SQL Server的虚拟内存的使用是来自于Bpool (缓冲池区),通过上面2个计数器可以知道. 一般而言增长和平稳是一前一后地.(请牢记:当应用程序启动了对AWE的支持, Pivate Bytes计数器不能反映总体SQL Server内存使用情况).如果Total Pages Perform计数器是水平的而Pivate Bytes计数器是向上倾斜的,这一般表示正在从MemToLeave (内存释放区)分配新的内存.这个分配过程会正常结束—例如:在SERVER中分配相关联的线程堆栈作为附加的工作线程,这也有可能是一个内部测COM对象或XPROC的内存泄漏.如果一个程序因为MemToLeave (内存释放区)耗尽而用完虚拟内存空间,这是由于内存泄漏或内存过度消费.(或者在MemToLeave (内存释放区)中最大空闲块降低到默认线程堆栈0.5MB以下),这样SERVER就不能产生新的工作线程,即使在sp_configure max worker threads 的值没有到.在这种情况下,如果SERVER需要产生新的工作线程来执行一个工作请求—比如:处理一个对SERVER的新的连接请求,这些工作将会延迟,直到SERVER可以产生新的线程或其他的线程可以使用.这样,在有足够的MemToLeave (内存释放区)释放或其他的工作线程可以有效的处理连接之前,系统会阻止一个用户连接到SERVER,因为这个连接会超时中止(time out).

内存分配器

在SERVER中一个内存的消费者初始化一个内存分配器,首先是产生一个内存对象来管理这些请求.当这个对象来分配这些请求,他在SERVER的内存管理器中,从Bpool (缓冲池区)或MemToLeave (内存释放区)来履行这些请求.如果这些请求小于8K,这些请求通常在Bpool (缓冲池区) 分配.如果请求需要8K或以上的内存空间, 这些请求通常在MemToLeave (内存释放区)分配.因为一个单独的内存对象可以用来执行多次内存分配.所以有可能一次内存分配正好在8K以下(包括管理对象的消费)的请求被分配在MemToLeave (内存释放区). 在SQL Server的处理空间中,内存消费者通常是内部的.换句话说,这些内存消费者和对象是SQL Server自己的规范需要消耗内存来执行任务,但也不一定都这样.也存在一些外部的消费者,就像我前面锁说的.通常,这些外部的内存消费者调用正常的Win32 API内存函数来分配和管理内存,并且从MemToLeave (内存释放区)分配内存空间,非常明显这是SQL Server程序中唯一有效的区域. 可是XPROCS有特殊的异常处理,当一个xproc调用Open Data Services(ODS) srv_alloc API函数,这完全和其他的内存消费者一样. 一般而言srv_alloc API函数从Bpool (缓冲池区)申请小于8K的内存,对于大的内存从MemToLeave (内存释放区)分配.


...:::小鸟巢:::...
小鸟--永远的好奇,不断的求知者
小鸟巢--小鸟聚集的地方
小鸟们的天堂,求知者的乐园
我们为您提供各种各样的资料
http://xnc.cn
http://lbns.org
ip地址已设置保密
2005-11-4 22:01:00
cmsea
帅哥哟,在线,有人找我吗?
天秤座10-12
ㄚっ小鸟っㄚ
帝国元帅
88888888
5446
46808
无门无派
2003年10月11日
4
 用支付宝给cmsea付款或购买其商品,支付宝交易免手续费、安全、快捷!QQ 点击这里发送电子邮件给cmsea访问cmsea的主页

发贴心情

内存管理者

当SERVER运行时,内存管理者检查物理内存的剩余有效容量,以保证WINDOWS和其他的应用程序可以可以平稳的运行.这个有效内存的大小在4MB和10MB直接变化.(在WINDOWS 2003中更接近10MB)并且这个基于系统内核加载和Bpool (缓冲池区)中的页生命周期.如果SERVER上的有效物理内存空间在这个阀值以下,SERVER会减少提交Bpool (缓冲池区)页来收缩内存物理存储的使用(假设动态内存分配是激活的).内存管理者也保证提交的内存页在指定的时间点后空闲,这样在接受到一个新的分配请求时,就不再需要等待内存分配.通过”空闲”,我的意思是:内存页提交后,但没有被使用.没有使用的提交Bpool (缓冲池区)页可以通过一个空闲页清单来跟踪.这样所有得新得页都来自空闲页清单, 内存管理者从Bpool (缓冲池区)预留区提交更多得页直到全部得预留区被提交.你看:Process:Private Bytes Perfmon 计数器缓慢增长(通常是成直线的)就是这个原因.

在多CPU系统中,没一个都有自己单独的空闲页清单,当一个空闲页被要求响应一个应用程序的请求,首先在当前的CPU的空闲页清单中满足分配的空间被检查,然后是其他CPU的空闲页清单.这样更好的利用每个处理器的本地缓存,提高了在多处理器的SERVER上提高稳定性.你可以通过SQL Server:Buffer Partition Perform对象监视指定的Bpool (缓冲池区)区,你可以可以通过SQL Server:Buffer Manager\Free Pages Perform计数器监视所有的Bpool (缓冲池区)区.

因此在SQL SERVER整个运行过程中,SQL SERVER的内存处理器(无论内存线程管理器或同其他的线程服务)监视系统的内存使用状态,确认合理的剩余空闲物理内存的数量给其他的系统和预留合理的空闲页响应新的内存请求.当SERVER使用AWE内存,有些内存状态必需改变. Bpool (缓冲池区)区开始通过SERVER的物理内存中获得和锁定内存,内存锁的数量的变化是根据服务器最大内存是否设置了.如果配置了, Bpool (缓冲池区)区试图根据最大的服务器内存锁住相应数量的内存.如果没有配置, Bpool (缓冲池区)区会锁住接近128MB内存的所有物理内存,只有少量的区域留给其他处理.然后Bpool (缓冲池区)区使用高于3G的物理内存(AWE内存)用作运行数据和索引的页文件. Bpool (缓冲池区)区根据需要映射物理内存和虚拟内存,因此可以被32位的指针引用.

概述

你已经知道了:SQL Server内存管理器是一个难点.理解一个程序是如何分配和管理内存是了解一个程序如何工作的基础.内存是非常重要的资源,它的有效利用是一个可靠应用程序设计的基本因素,懂得一个应用程序内存管理机制会是你的程序设计如虎添翼.

一个开发者,他是如何影响你呢?理解SERVER的内存管理机制赋予你如何写一个高效的应用程序和解决一些和内存相关联问题的洞察力. 比如说,在一个提高客户端连接速度的调试中,你提高SQL Server的默认网络包的大小为8K., 立即,SQL SERVER立刻开始在ERROR LOG中写错误信息,提示预留虚拟内存在MemToLeave (内存释放区)区有问题.在看到这样的信息后你立刻会知道这个改变至少是问题的一部分,因为你知道分配8K或更多的内存是在MemToLeave (内存释放区)区. 这样SQL Server连接相关联的缓存也是来自这个区域,因为你已经配置网络包的大小太高了.配置默认的网络包适合于.NET framework的SQLClinet Provider 8KB.这种情况并不象听起来那么合理.实际上,这是非常常见的问题,由于MemToLeave (内存释放区)缺乏内存空间而引起的,因为网络包的大小太大,至少有些部分是这样的.

同时,了解SQL Server划分内存的方法可以帮助你了解你定制在SQL Server中运行的代码是否在系统资源的临界值,比如数据缓存. 比如说,你建立一个扩展存储过程调用SRV_PRO()函数来分配内存.假设,暂时你代码中分配的缓存小于8KB.根据我们前面的讨论,我们知道扩展存储过程是从Bpool (缓冲池区)来分配内存.—可以用作数据缓存.

了解SQL Server是如何管理内存的,可以帮助我们按大小排列系统的开始顺序.这可以帮助你计算你所需的物理内存的数量和如何分配和分区给SQL SERVER.比如:良好的理解AWE内存分配和应用程序的内存调整的相对的优势和缺点,可以帮助确定你的服务器是否需要超过3GB的物理内存和是否需要在启动时加/3GB的参数.

构思和配置SQL Server的内存管理机制有一个主要的冲突在于构思和配置在SQL Server上运行的应用程序,了解SERVER是如何运行的可以帮助你设计,建立和测试基于SQL Server的应用程序.


posted on 2006-06-20 16:39 无为斋 阅读(784) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理