SQL 内存分配

一、向操作系统申请内存的方式

  有2种申请方式:

1、Reserved/Committed pages

  应用程序调用Windows API,预先申请保留(Reserve)一块内存空间。Reserved Memory(保留地址)留着将来使用,且这块已经保留的空间不能被其他程序访问,不然会出现访问越界的报错提示。此时只是保留一段虚拟地址空间(VAS)上面的一段地址,尚未真正分配物理内存空间。

  在需要使用的时候,再一点一点地将保留(Reserve)的内存页面正式提交(Commit)给应用程序使用。此时,将正式在物理内存中申请一段有效的地址,提交的页面在访问时最终转换到物理内存中的有效页面。

  分两步来预留和提交内存,通过推迟页面提交来减少物理内存的使用。这对于需要潜在、大量和连续内存缓冲区的应用程序是很有用的。地址空间可以被保留,在需要的时候再提交,而不是为了整个区域提交页面。这种技术在SQL Server中用来缓存数据页面。


2、Stolen pages

  直接用Commit方式从地址空间申请内存,称为Stolen方式。这部分内存也是正常内存,只是每次需要一点内存就直接在物理内存中申请一部分页面,类似于“偷”。

  SQL Server中除了Database Cache是先Reserve再Commit,其它所有的内存使用基本上都是直接Commit,都是Stolen。

  通过启用AWE功能可以使32位操作系统访问4GB以上的物理内存,但这部分内存不可以用于Stolen方式。意味着仅Database Cache可用。



二、SQL Server的内存用途

  计数器“SQLServer:Memory Manager:Target Server Memory(KB)”为服务器可供SQL Server使用的内存量。一般是由SQL Server能访问到的内存量和SQL Server的配置中的Max Server Memory值中的较小值算得。

  SQL Server的内存主要分配给以下4大部分:

1、database cache

  SQL Server中的页面都是以8KB为一个页面存储的。当SQL Server需要用到某个页面上存储的数据时,它会将该整个页面读到内存中,使用完后会缓存在内存中。如果该页面被修改,变成“脏页”,就要等待Checkpoint或Lazy Writer集中处理。如果遇到内存压力,SQL Server就需要释放一些“旧”的页面。

  Database Page都是采用先Reserved后Commit的方式申请的。通常这块缓冲池最大,使用频率也最高。


2、线程(thread)内存

  存放进程内每个线程的数据结构和相关信息消耗的内存,每个线程需0.5MB的内存。

  线程内存申请,一般都是按Stolen方式申请的。


3、各类内存消费者(Consumer)

  Consumer的内存申请,一般都是按Stolen方式申请的。也就是相当数量的stolen pages都用在这里。包括:

(1)Connection,每一个连接的数据结构和相关信息。

(2)General,语句的编译、范式化、每个锁数据结构、事务上下文、表格和索引的元数据等。

(3)Query Plan,语句和存储过程的执行计划。和Database cache类似,SQL Server也会将执行计划缓存以供将来使用,减少编译时间。

(4)Optimizer,生成执行计划的过程中消耗的内存。

(5)Utilities,像BCP、Log Manager、Parallel Queries、Backup等比较特殊的操作消耗的内存。


4、第三方代码消耗的内存

  SQL Server的进程里,会运行一些非SQL Server自身的代码。例如:

(1)用户定义的CLR。

(2)Extended Stored Procedure代码。

(3)Linked Server需要加载的数据连接驱动。

(4)调用SQL Mail功能需要加载的MAPI动态库。

  第三方代码的内存申请一般是按Stolen方式申请的,偶尔有例外。例如,个别CLR中可能会用Reserved/Commit的方式申请。

  这部分内存不是SQL Server自身代码申请的,所以SQL Server并不清楚它们申请了多少内存。但是作为一个进程,Windows知道SQL Server申请的所有内存,所以也能够计算这一部分的内存使用。



三、缓冲池

1、框架

  SQL Server 2000缓冲池的框架如下:

230503658.jpg

  根据上图,SQL Server的主要内存组件是缓冲池(buffer pool),除了数据缓存之外,所有的缓存都使用共同的缓存框架。该框架包括存储(store)集和资源监视器。存储集包括3种类型:缓存存储、用户存储、对象存储。

  缓存存储的主要示例是计划缓存(过程和查询计划缓存);用户存储实际上与用户无关,它的主要示例是元数据缓存,对象缓存的一个使用示例是SNI(它使用对象存储来共用网络缓冲区)。


注:SQL Server Network Interface(简称SNI)
  SNI是在服务器和客户端之间建立网络连接的一种协议,他提供一组在数据库引擎和SQL Server客户端使用的API函数。SNI代替了SQL Server2000下的Net- Libraries组件和MDAC组件。

  SQL Server支持共享内存(Shared memory)、TCP/IP、命名管道(Named Pipes)、虚拟接口适配器(Virtual Interface Adapter,即VIA)四种协议。不推荐使用VIA,SQL Server 2012移除了对VIA的支持。

  一旦建立连接,SNI就会向服务器的端点(Endpoint)创建一条安全的连接,用来进行数据的请求和返回。


2、计数器

(1)计数器“SQLServer:Memory Manager:Target Server Memory(KB)”表示SQL Server能够使用的动态内存总量。

(2)计数器“SQLServer:Memory Manager:Total Server Memory(KB)”表示SQL Server缓冲区提交的内存。不是SQL Server总的使用内存,只是Buffer Pool中的大小。

(3)计数器“SQLServer:Buffer Manager:Database Pages”表示Buffer Pool中Database Cache的大小,即数据库被加载到内存的这部分大小。

(4)计数器“SQLServer:Buffer Manager:Free Pages”表示Buffer Pool中所有的空闲可用的总页数。

(5)计数器“SQLServer:Buffer Manager:Stolen Pages”表示Buffer Pool中Stolen的大小,即用于其他用途,包括过程缓存。

(6)计数器“SQLServer:Buffer Manager:Free Pages”表示Buffer Pool中当前可用的页数。

(7)计数器“SQLServer:Buffer Manager:Total Pages”表示Buffer Pool的总大小(等于Database Pages+Free Pages+Stolen Pages)。该值乘以8KB,应该等于计数器“Memory Manager:Total Server Memory”的值。


注:“SQLServer:Buffer Manager:”计数器组一共包括以下计数器:AWE lookup maps/sec、AWE stolen maps/sec、AWE unmap calls/sec、AWE unmap pages/sec、AWE write maps/sec、Buffer cache hit ratio、Checkpoint pages/sec、Database pages、Free list stalls/sec、Free pages、Lazy writes/sec、Page life expectancy、Page lookups/sec、Page reads/sec、Page writes/sec、Readahead pages/sec、Reserved pages、Stolen pages、Target pages、Total pages 。



四、内存的页面

  SQL Server自己申请的内存,有两种内存单位。

1、Buffer Pool(缓冲池)

  所有可以分成小于或等于8KB为一个单位的内存申请,SQL Server就分配给一个8KB页面。所有这些页面都集中管理,这块内存被称为Buffer Pool。一次一个页面的这种分配,被称为Single Page Allocation。

(1)Database Page都是以8KB为单位进行申请的。

  也就是说,Buffer Pool的设计和SQL Server的数据页面大小一致,能够有效地分配和管理SQL Server进程里的内存。对于SQL Server来讲,大部分的内存需求都可以以8KB为单位,放在Buffer Pool里。


(2)各类Consumer大多数以8KB为单位进行申请。

  对于Connection,与Network Package Size(客户端和SQL Server通信的每个数据包的大小)有关系。默认的连接的数据包是4KB,因此输入/输出缓存会放在Buffer Pool。一台SQL Server的默认Network Package Size大小可以由sp_Configure控制。但是任何一个客户端都可以指定它建立的连接自己的Network Package Size。

  对于General,绝大部分内存,例如每个锁的数据结构、事务上下文、表格和索引的元数据等,都会以8KB为单位申请。

  对于Query Plan、Optimizer、Utilities等,和General类似,绝大部分内存使用都会在Buffer Pool里。


2、Multi-Page(保留内存)

  对于大于8KB为一个单位的内存申请,SQL Server把它们集中在另外一个区域,这块内存被称为Multi-Page(以前叫做MemToLeave)。这种分配被称为Multiple Page Allocation。这个区域不同于Buffer Pool,因为在这个区域中分配的内存很大一部分不受SQL Server控制。即,只在SQL Server内部分配,却由加载在SQL Server内部的其它dll来分配。


(1)线程的内存每个都以0.5MB的方式申请,自然是放在MemToLeave中。


(2)各类Consumer仅少量使用Multi-Page。

  对于Connection,如果客户端特别设置了超过8KB或更大,输入/输出缓存会放在Multi-Page里。

  对于General,如果偶尔一个语句特别长,它的编译和范式化需要使用大于8KB为单位的内存,这会使用Multi-Page。

  对于Query Plan、Optimizer、Utilities等,遇到特别长的语句,它的Query Plan、Optimizer等内存使用一部分Multi-Page。


(3)第三方代码使用Multi-Page。

  由于SQL Server不清楚这些代码申请的内存大小,所以SQL Server把它们申请的内存都放在Multi-Page里。


说明:

(1)MemToLeave。在32位操作系统,SQL Server启动时会尝试保留我们所配置的MemToLeave大小(包含Worker Thread所需)的地下空间,然后把其它地址空间都给了Buffer Pool,而剩下的这块空间就可以由第三方的dll或者其它加载在SQL Server的内部代码来使用了。

(2)Multi-Page。在64位操作系统中,地址空间可以理解为无限大,SQL Server不再控制Multi-Page这段空间的大小。所以就不再使用MemToLeave这个名词。


3. Large Page(大页面)

  SQL Server有可能申请一种Large Page。由于历史原因,在Windows层面,每一个页面都是4KB,为了建立起页式内存管理的映射关系,需要有两级或者三级页表,而整个转换过程是需要多次的内存访问。从某种程度上来说,这部分的开销是昂贵的,可以进一步优化。为此,计算机体系结构里引入了转换后页表(TLB)。但是这块TLB缓存的大小是有限制的,为了能够通过这段固定大小的缓存来尽可能访问更多的内存映射操作获益,SQL Server引入Large Page的内存,让单次映射能够访问的内存数量变大,以期获得更好的性能。



五、32位操作系统的内存限制

  如果使用了AWE技术,可以将系统的扩展地址空间达到64GB,但由于AWE扩展出来的地址只能用Reserved/Commit方式申请,因此对于SQL Server来说,AWE扩展出来的内存主要用于给database pages作为缓存。

  由于32位的SQL Server会在启动的时候分配好Multi-Page的大小,而且比较小,默认是384MB,因此对于32位的SQL Server比较容易发生Multi-Page Memory的压力。

  线程堆栈、内存锁、过程计划等所需的内存都不能在AWE中分配。SQL Server 分析服务不能利用AWE映射的内存。

  64位的SQL Server忽略AWE选项。


本文出自 “我们一起追过的MSSQL” 博客,保留此出处http://jimshu.blog.51cto.com/3171847/590409


你可能感兴趣的:(SQL内存)