为什么 dm_os_memory_clerks 在一个 NUMA 节点上具有 MEMORYCLERK_SQLCLR 值?

msg*_*sme 8 sql-server sql-clr sql-server-2014 numa

我们正在使用 SQLCLR 存储过程来激活服务代理,我想监视 CLR 代码使用的内存。查看sys.dm_os_memory_clerks,我看到只有 NUMA 节点 1 具有与该MEMORYCLERK_SQLCLR类型关联的任何页面。服务器有两个 8 核 CPU,运行 SQL 2014 CU6。

这是预期的吗?或者我应该像我一样看到两个节点上使用的内存MEMORYCLERK_SQLBUFFERPOOL

询问:

SELECT DOMC.memory_node_id
    , DOMC.pages_kb
    , DOMC.virtual_memory_reserved_kb
    , DOMC.virtual_memory_committed_kb 
FROM sys.dm_os_memory_clerks DOMC where type = 'MEMORYCLERK_SQLCLR'
Run Code Online (Sandbox Code Playgroud)

结果:

memory_node_id pages_kb             virtual_memory_reserved_kb virtual_memory_committed_kb
-------------- -------------------- -------------------------- ---------------------------
0              88232                12607744                   1408652
1              0                    0                          0
64             0                    0                          0
Run Code Online (Sandbox Code Playgroud)

Sol*_*zky 4

不幸的是,没有关于 SQLCLR 内存使用细节的大量信息。然而,我确实发现以下两个资源作为起点很有帮助:

\n\n\n\n

从这些内容中,并浏览各种 DMV 和 MSDN 页面来解释(好吧,这没有太多解释,但从技术上讲,它比什么都没有)这些 DMV 是如何工作的,我将下面显示的查询放在一起。从在几个不同的系统上运行这些数据来看,SQLCLR 内存分配似乎集中在一个特定的节点上memory_node_id,但在其他节点上仍然有一些分配,至少在 Proc Cache 方面是这样。因此,就目前而言,除非有人有相反的证据或信息,否则您所经历的一切都是“预期的”。

\n\n
\n\n

此查询报告基本信息:

\n\n\n\n
SELECT domc.*\nFROM   sys.dm_os_memory_clerks domc\nWHERE  domc.[type] LIKE \'%CLR%\'\nAND    domc.[memory_node_id] <> 64;\n
Run Code Online (Sandbox Code Playgroud)\n\n

您会注意到,如果不指定一个特定的[type],则还有其他一些可能会占用一些内存。我见过的总共4种类型是:

\n\n
    \n
  • MEMORYCLERK_SQLCLR,
  • \n
  • MEMORYCLERK_SQLCLRASSEMBLY
  • \n
  • CACHESTORE_CLRPROC
  • \n
  • CACHESTORE_CLRUDTINFO
  • \n
\n\n

如果您想知道为什么我要过滤掉[memory_node_id]64 个,请运行以下命令:

\n\n
SELECT * FROM sys.dm_os_nodes;\n
Run Code Online (Sandbox Code Playgroud)\n\n

您将看到node_id 64 是DAC(专用管理员连接)。

\n\n

下面将为您提供两个重要字段的总计。请注意,这些字段在 SQL Server 2012 中发生了更改,因此您需要选择适合所使用的 SQL Server 版本的字段:

\n\n
-- SQL Server 2012, 2014, and 2016:\nSELECT SUM(domc.pages_kb) AS [TotalPagesKb],\n       SUM(domc.virtual_memory_committed_kb) AS [TotalVirtualMemoryKb]\nFROM   sys.dm_os_memory_clerks domc\nWHERE  domc.[type] LIKE \'%CLR%\'\nAND    domc.[memory_node_id] <> 64;\n\n-- SQL Server 2005, 2008, and 2008 R2:\nSELECT SUM(domc.single_pages_kb + domc.multi_pages_kb) AS [TotalPagesKb],\n       SUM(domc.virtual_memory_committed_kb) AS [TotalVirtualMemoryKb]\nFROM   sys.dm_os_memory_clerks domc\nWHERE  domc.[type] LIKE \'%CLR%\'\nAND    domc.[memory_node_id] <> 64;\n
Run Code Online (Sandbox Code Playgroud)\n\n

下一个查询显示“memory_clerks”和“memory_objects”之间的关系:

\n\n
SELECT domc.*, N\' \xe2\x96\x88 \' AS [ \xe2\x96\x88 ], domo.*\nFROM   sys.dm_os_memory_clerks domc\nLEFT JOIN sys.dm_os_memory_objects domo\n        ON domo.page_allocator_address = domc.page_allocator_address\nWHERE  domc.[type] LIKE N\'%CLR%\'\nAND    domc.[memory_node_id] <> 64;\n
Run Code Online (Sandbox Code Playgroud)\n\n

以下查询是第一个查询的更集中的版本(更类似于问题中的查询),但是 SQL Server 2012 中的字段发生了更改,因此您需要选择适合其正在使用的 SQL Server 版本的查询用于:

\n\n
-- SQL Server 2012, 2014, and 2016:\nSELECT domc.memory_node_id,\n       domc.[type],\n       domc.pages_kb,\n       domc.virtual_memory_committed_kb\nFROM   sys.dm_os_memory_clerks domc\nWHERE  domc.[type] LIKE \'%CLR%\'\nAND    domc.[memory_node_id] <> 64;\n\n-- SQL Server 2005, 2008, and 2008 R2:\nSELECT domc.memory_node_id,\n       domc.[type],\n       (domc.single_pages_kb + domc.multi_pages_kb) AS [pages_kb],\n       domc.virtual_memory_committed_kb\nFROM   sys.dm_os_memory_clerks domc\nWHERE  domc.[type] LIKE \'%CLR%\'\nAND    domc.[memory_node_id] <> 64;\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

更新:

\n\n

我在双处理器系统上做了一些额外的测试,方法是创建 2 个数据库,并使用静态变量将 80 MB 加载到每个数据库中。我创建了两个数据库而不是一个数据库,以查看 AppDomain 是否必须保留在一个内存节点上,是否能够至少将另一个 AppDomain 放置在另一个内存节点上以便分散数据。结果:

\n\n
    \n
  • 两个 DB(以及两个 AppDomain)的所有 160 MB 都进入内存节点 0
  • \n
  • 所有 160 MB 都进入虚拟内存,而不是物理内存。只是[virtual_memory_committed_kb]领域sys.dm_os_memory_clerks增加了。而“任务管理器”中的“Commit Size”栏也反映了这一增长。
  • \n
\n