最近帮客户解决发布订阅的问题时,突然遇到这样一个问题发布订阅中报下面的错误,另外执行alter table 操作时也会报错 :
问题很奇怪发布订阅和CLR有什么关系?memtoleave内存是个啥?回忆学习体系架构的时候,确实看到过memtoleave内存,但是是什么已经完全想不起来了,所以拿起书本回味一下学习的快感...
---------------转载请注明出处------------http://www.cnblogs.com/double-K/p/5049417.html--------------------
抛开问题我们先看一下SQL SERVER的内存结构:
1.从操作系统层面看SQL SERVER内存分配:windows 和SQL SERVER的关系就像君与臣一样,windows的统治下SQLSERVER和其他应用如notepad并无两样,当操作系统级别都内存紧张的时候SQL SERVER的内存一样会紧张。所以了解WINDOWS的内存结构同样重要。
-
-
- Virtual Address Space (虚拟地址空间)
- Physical Memory (物理内存)
- Reserved Memory (保留内存)
- committed Memory (提交内存)
- Shared Memory (共享内存)
- 等等好多种有兴趣的可以自己看一下
-
2.SQL SERVER内存的使用分类:
-
-
- 按用途:
- database cache :存放数据页面的缓冲区,SQL SERVER数据库里的数据都是以8KB为一个页面存储的,当有用户需要使用到这个页面的时候SQL SERVER就会把整个也都调入内存。所以8KB是数据访问的最小单元。
- 各类consumer :SQL SERVER各类组件,他们必须申请内存来支持他们完成工作,如:SQL SERVER需要为每一个连接分配一个数据结构,存储关于连接的信息,还会分配输入和输出的缓冲池(客户发送的指令/指令所获取的结果,等待客户端取走),语句的缓存计划等等。
- 线程内存 : SQL 会为进程内的每个线程分配0.5MB的内存,用以存放线程内的结构和相关信息。
- 第三方代码申请的内存 : 如CLR、LINKEDSEVER、COM等,这部分内存一般不会很大,但是假如一个linked server的分布式查询需要从远端取回大量的数据,那么这块内存就会使用的很大。所以这块内存的监视也不能忽视。
- 按申请方式 :
- 预先reserve 一块大内存,然后在使用的时候一小块一小块的commit
- 直接从地址空间申请commit,这种方式成为stolen。(AWE功能无效,扩展出来的内存只能用于database cache,其他还是需要在2GB里解决)
- 按申请大小 :
- 小于等于8KB (buffer pool)
- 大于8KB (multi-page 2008以前叫memtoleave)
- 按用途:
-
我们以按照大小的分类作为说明:申请小于等于8KB 这些页面都集中管理,这块内存称为 buffer pool,另一部分申请大于8KB的称为multi-page(memtoleave),memtoleave这块区域的内存分配很大一部分不受SQLSERVER本身控制,或者可以说只在SQL SERVER内部分配,但是却是由加载在SQL SERVER内部的其他DLL来分配的,如CLR。
32位的年代启动时需要保留我们配置需要的memtoleave大小(包含worker thread所需)的地址空间,然后把其他的都给buffer pool。
64位时代以后由于地址空间可以理解为无限大,所以SQL SERVER不再控制memtoleave这段空间的大小,甚至已经可以抢夺database cache了。
以一个表格总结一下:
类型 | database cache | consumer | 第三方代码 | threads |
reserved/commit | 是 | 一般不是 | 一般不是 | 不是 |
stolen | 不是 | 是 | 是 | 是 |
buffer pool | 所有 | 绝大部分 | 没有 | 没有 |
memtoleave | 没有 | 一小部分 | 所有 | 所有 |
---------------转载请注明出处------------http://www.cnblogs.com/double-K/p/5049417.html--------------------
简单的说明了一下SQL 的内存,有几点需要注意的也简单提一下:
1.WINDOWS不缺内存SQL 就不会缺内存吧?
答:这个是很错误的(1)如果是32位,由于虚拟地址空间的限制SQL 可能无法继续申请内存。有人会说我可以开AWE,前文也提到过AWE不是万能的,有64位为什么还要选32位呢? 对吧。(2)SQL SERVER很可能设置了max server memory约束了SQL 继续申请内存的能力,这个真遇到过,256G内存的服务器 max server memory 被设置成了2个G。
-
- 2.我们设置SQL 的最大内存 为20G,为什么有的时候观察sql进程的内存使用会超过20G?是不是这个没用呢?
答:属性->内存->最大内存 (max server memory)设置的其实buffer pool的最大值,里面没有包含memtoleave这段空间的大小,所以有的时候会看到SQL 使用的内存超过了设置的max server memory
- 3.我这是一台SQL SERVER专用服务器所以不需要设置max server memory,内存都给SQL SERVER。
- 答:这个问题是好多用户遇到的问题,看似没有问题,但是忽略了一点 SQL SERVER是一个很喜欢内存的应用所以很可能吃掉大量内存导致windows系统没有足够内存使用,那么这时候君臣关系就体现的淋漓尽致了,君(windows) 要臣死(释放内存)臣不得不死呀...这个释放在一定程度上可不是单单让windows够用了,很可能导致SQL内存陡降,以致SQL 短时间假死(操作无响应),一般我比较推荐操作系统20% ,SQL SERVER 80%如果服务器还有其他应用还要在SQL 中减掉应用所占的内存。
- 2.我们设置SQL 的最大内存 为20G,为什么有的时候观察sql进程的内存使用会超过20G?是不是这个没用呢?
---------------转载请注明出处------------http://www.cnblogs.com/double-K/p/5049417.html--------------------
说了这么多回到我开篇的问题上,为什么出现这个情况memtoleave内存不足呢?看完文章也许你已经有了答案。
我说一下我排查问题的步骤,当客户发给我报错截图的时候我第一反应必须是了解客户的环境,因为不能远程所以我询问了操作系统版本SQL 版本,补丁及内存设置等等...告诉我64位的WINDOWS SERVER2008 ,SQL SERVER2008R2,遗憾的是当时客户没有select @@version确认SQL 版本,我也理所当然的认为装的肯定是64位SQL SERVER呀!!经过翻阅资料网上寻找答案始终想不明白为什么会出现这个显现...最后再次要求客户确认SQL 版本时才发现64位操作系统竟然误安装32位SQL SERVER 这下问题瞬间明了。
这个32位memtoleave的内存初始是多大呢?256M + 256(个thread) X 0.5MB = 384MB,可以通过修改启动参数 + -g 1024 (分配1024MB)解决这个问题,但是这个问题的根本不是修改启动参数,这仅仅是表名现象,最终的操作必然是重新安装SQL SERVER x64 !!!当然这会对用户的应用造成很大的影响。
---------------转载请注明出处------------http://www.cnblogs.com/double-K/p/5049417.html--------------------
以为这个案例我突然发现自己的体系结构如此之脆弱...遇到问题虽然见过却没有完善的知识体系来支撑,所以准备再次学习一下SQL 内存篇!!同时也会奉上后续学习文章!!
哦了~~~