Dom*_*her 11 sql-server memory sql-server-2012
我有一个 SQL Server 2012 实例使用了更多的 RAM。
SQL Server 进程使用大约 22.5GB RAM:
该实例配置为最大使用 10GB:
这比预期的要多得多。(这将导致服务器崩溃,我们必须重新启动才能恢复)。
我用这个查询检查了内存使用情况(职员):
select type, name, pages_kb/1024.0/1024.0 "size Gb" from sys.dm_os_memory_clerks
order by pages_kb desc
Run Code Online (Sandbox Code Playgroud)
SQL Server 似乎只使用了大约 7GB RAM:
我知道它是 SQL Server 的旧版本(遗憾的是它没有修补到最新版本),但我无法找到有关 SQL Server 2012 SP2 中内存泄漏的任何明确文档。
我应该在哪里查找为什么 SQL Server 使用了大约 200% 的资源?
此实例上有一个链接服务器。很多使用 SQL 驱动程序(SQLNCLI 和 SQLNCLI11),但也有一些使用我以前从未见过的“HFSQL 的 PC SOFT OLE DB 提供程序”。
有什么方法可以“证明”这个驱动程序有问题吗?客户端可能不会同意基于假设更改设置,因此如果有任何方法(除了禁用之外)可以清楚地显示链接服务器正在使用多少 RAM,那将是无价的。
Dav*_*oft 11
dm_os_memory_clerks 没有显示内存这一事实强烈表明内存是在 SQL Server 引擎外部分配的。
“HFSQL 的 PC SOFT OLE DB 提供程序”
那将是罪魁祸首。许多第 3 方 OleDb 提供程序并未针对长期进程进行强化。桌面应用程序中的小内存泄漏很少会被注意到,因此他们通过测试却没有发现问题。
最好的解决方案是将 OleDB 驱动程序移至短期进程,例如 SSIS 包、PowerShell 作业或类似进程。如果这不可能,您可以尝试将 OleDb 提供程序推到进程外,同时仍然使用链接服务器,清除“允许进程内”标志并执行一系列 DCOM 配置(请参阅例如设置链接服务器-process OLEDB 提供程序),或使用SSIS 数据流目标并将链接服务器替换为
SELECT * FROM OPENQUERY([Default Linked Server for Integration Services], N'Folder=Power BI;Project=SSISPackagePublishing;Package=Package.dtsx')
Run Code Online (Sandbox Code Playgroud)
另一个解决方案是按计划恢复 SQL Server。
有什么方法可以“证明”这个驱动程序有问题吗?
没有任何东西可以在 SQL Server 的控制之外跟踪本机代码内存分配。我能想到的证明这一点的唯一方法是反复访问链接服务器,看看是否可以触发内存泄漏。
如果您将支持案例升级到足够高的程度,他们可能会最终找到泄漏点。
扩展我最初对大卫的回答留下的评论:
几个关键点。首先,并非所有内存对象和代理都会出现在 DMV 中,因此技术上可以是 SQL Server 分配。其次,您要做的是收集用于内存分配的 xperf/wpr,然后通过 AIFO(内部分配,外部释放)以及峰值来切割数据。这应该为您提供实际分配虚拟内存的模块和调用堆栈。第三,可以通过 GFLAG 打开堆跟踪,但这通常不会提供与 xperf/wpr 一样好的结果。
尽管它不会给出直接答案,但它应该是如何获取数据以找出问题根源的指南(尽管这可能与根本原因不同)。
我写了一个小重现来模拟你的情况......
我将最大服务器内存设置得非常低(无论如何它都是一个小虚拟机),线程数非常低,并确保内存中没有任何内容。请记住,线程堆栈、模块等不计入最大服务器内存,因此使用完整的缓冲池时,您将始终显示高于最大服务器内存值。
我创建了一个快速重现,这会消耗大量内存。现在,我正在做一些OP缺少的事情,那就是因为我正在查看内存分配的类型(尽管它们最终都会经过虚拟分配[除了我在这里没有使用的一些物理页面调用])这样我就可以知道正在进行什么类型的分配,这有助于排除故障。
现在我们的内存使用量增加了很多(从 470 MB 到 2.5 GB):
由于这是一个简单的重现,因此我设置了 ETW 捕获并捕获内存使用之前、期间和之后的时间。根据内存分配发生的速度(无论是需要 1 天、1 小时还是 1 个月),您收集数据的设置可能会发生变化。
我可以看到这是专门分配的堆数据,它排除了 SQL Server 内部的许多不同项目(尽管堆仍然用于各种项目),它确实有助于查找位置。
由于我专门配置了 ETW 捕获来获取内存分配(VirtualAlloc、HeapAlloc 等),因此它可用于检查所谓的“内部分配、外部释放”或 AIFO 内存,这意味着内存在捕获期间已分配并继续存在超过捕获结束时间。如果我使用堆栈、提交类型、符号等项目设置环境,则可以看到大部分内存正在使用的位置。下面是按提交类型 (AIFO) 和堆栈划分的示例。请注意,发生这种情况的方式有多种,因此可能会因 1,000 次分配而死亡,或者一次巨大的分配,也可能介于两者之间。
您会注意到,对于标记#1,有一个 2 GB 分配未完成(它继续存在)。标记 #2 显示创建它的堆栈。我想提请您注意仍然是 PID 756 的进程,并且这仍然是 SQL Server,但是您会看到通过使用公共符号,存在此 2 GB 分配的堆栈,其中显示了对以下内容的调用RtlpAllocateHeapInternal
:顾名思义,它在堆上分配空间(在本例中为默认进程堆),这与上面显示正在分配的堆数据的屏幕截图中的数据一致。如果我们查看 ETW 数据中的堆栈,它表明这是通过一个名为的模块分配的,CSSDet.dll
该模块在 Microsoft 公共符号服务器上没有符号,这表明这不是 Microsoft 产品。
同样,这是一个简单的重现,我编写了 DLL,但是如果在实际环境中出现这种情况,下一步将是检查 DLL 制造商并联系他们,另外您还需要调用堆栈分配,他们可以使用它来帮助追踪代码中的问题。
您能否添加一些有关 ETW 设置的详细信息以捕获和分析此数据?
OP 执行此操作的最简单方法是 wpr 捕获内置配置文件(这使得它更容易,尽管它确实收集了更多数据)。wpr -start VirtualAllocation
[...]您如何加载并运行自定义.dll [..]
我使用了典型的防病毒/恶意软件路线,并为用户模式进程编写了自己的模块注入器。我并不是为了这个特定目的而编写它,但它可以用于快速重现。请注意,我还调试了 EKM 模块中的相当多的内存泄漏,这是第三方提供商的另一个常见模块加载点。