问题标签 [unmanaged-memory]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c# - C# 调用非托管 DLL:在 DLL 中引发 Bad_allocation 异常
我的任务是更新旧的 32 位 C# 应用程序,以支持将 4K/UHD 图像(jpg、tiff 等)转换为 YUV 图像以进行进一步处理。我们完成转换 SD/HD 内容的方法是使用 DLL 来调用开源工具 FFmpeg 来执行操作。这是通过执行以下操作来完成的:
- C# 应用程序将图像文件传递给 DLL
- 然后,DLL 分配捕获新转换图像所需的内存(每帧字节数 => 1080p=8.2mb,2160p=33.2mb)
- 然后 DLL 通过传入指向文件的指针和分配的内存缓冲区来调用第 3 方工具
- 一旦函数调用返回,我们将转换后的图像保存到文件中
- 清理(关闭文件、释放内存等)
- 无论成功与否,DLL 都会返回 true/false 布尔值。
无论如何,它还有很多东西,但简而言之就是这样。我遇到的问题是在通过分配 33mb 更新 DLL 以支持 4K/UHD 之后,我现在得到一个 System.Runtime.InteropServices.SEHException; 使用 VS 调试器,我在这个非托管 C++ 行上观察到了一个 bad_allocation 异常
UInt32 *pixGroupFrameBuf = new UInt32[bytesPerFrameHdr/BYTES_PER_INPUT_PIXEL]; //Where UInt32[bytesPerFrameHdr/BYTES_PER_INPUT_PIXEL] is 33177600 bytes=>33mb
如果我转换 1080p jpg 图像,它只分配 8mb。如果我将我的 4K jpg 图像转换为 1080 YUV 图像,它也只分配 8mb,它也可以;所以它不是我传入的源文件。经过一些实验,当我尝试分配 28mb 并抛出异常通过 30mb 时,问题变得间歇性。在 Windows 资源监视器工具下查看我的可用空闲内存,我发现我的系统还剩下大约 4GB。
此外,由于我们的旧 C# 应用程序是非常大的 GUI 应用程序,我决定创建一个更简单的 32 位 C# 应用程序,它只以相同的方式调用 DLL,以便我可以更快地调试并更好地查明问题。我发现我的新 C# 项目可以正常工作。我什至可以将分配增加到更大的数量,并且它可以毫无问题地分配请求的大小(只要我将其保持在 2GB 以下并且有足够的可用内存)。因此,问题在于调用 DLL 的更大的 C# GUI 应用程序。
有了这个,我很难理解我们的遗留 C# 应用程序发生了什么以及接下来要尝试什么。是否有人可能对可能发生的事情有所了解或建议我接下来可以查看或尝试的内容?
...这是我的系统资源的图片,因此您可以看到我的两个 C# 应用程序之间的内存使用情况。*_Menu.vshost.exe 是我们的旧版应用程序。convert.vshost.exe 是我的测试应用程序。如您所见,我们的旧版 C# 更大,但不是千兆字节。
最后说明:
- 我不愿意将 32 位 C# 应用程序转换为 64 位。我知道它很旧,应该更新,但目前要做的工作太大了。此外,我相信已经证明这不是 32 位问题,因为我的测试应用程序有效。
- 我愿意在 C# 应用程序中分配内存并将其传递到 DLL 以供它使用,而不是在其中分配。如果我不能按设计解决它,那是我的备用计划。
- 我不相信我在 DLL 中有内存泄漏,因为我使用 Resharper dotMemory 对其进行了分析
- 如果您帮不上忙,感谢您愿意为实现这一目标而敞开心扉!
.net - 在 .NET 中,如何为 OLE 分配的以 0 结尾的非托管 Unicode 字符串释放内存?
通过使用IEnumSTATSTG::Next方法,我在STATSTG结构的pwcsName字段中获得了一个指向以 0 结尾的 Unicode 字符串的指针。
它的内存是由 OLE 分配的,但调用者有责任释放它。
我假设内存是使用非托管 COM 任务内存分配器分配的,但我在这里可能错了。如果假设是正确的,我会使用Marshal.FreeCoTaskMem(PtrToString)
释放该内存。
然而,论点是一个IntPtr
. 在 VB 中,我试图获得一个IntPtr
with
语法被接受,但字符串类型错误 ( Input string is not in a correct format.
)
因此我的问题:
我如何正确地IntPtr
从结构记录的字段中获取一个?
或者更一般地说,我怎样才能成为好公民并防止潜在的内存泄漏?
这是相关代码:
c# - 如何在 C# 中定位非托管内存泄漏
我对我们的应用程序中的内存泄漏感到困惑。它只发生在客户的机器上,或者至少在我的机器上重现它的测试失败了。幸运的是,如果发生未处理的异常,我们的应用程序会将一些数据收集到日志文件中,如果它是 OOM,则写入转储文件。它是一个 32 位 C# WinForms 程序。
到目前为止我能找到什么:
该进程在崩溃之前运行了大约三个小时
在崩溃时收集了以下值:
currentProcess.WorkingSet64 = 1,8 GB currentProcess.VirtualMemorySize64 = 2.0 GB currentProcess.PrivateMemorySize64 = 680 MB
这是让我认为它不受管理的第一点。为什么 WorkingSet 比 PrivateMemory 高这么多?我猜可能是第三方dll?
因此,为了进一步分析,我将内存转储加载到 WinDbg
SOS 命令 !analyzeoom 告诉我:由于 GC 堆上的分配,没有托管 OOM。为了验证,我查看了 !eeheap,它告诉我 GC 堆的总大小为 217 MB,Loader 堆的总大小为 38 MB
现在我想看看所有的堆。但是使用 !heap -s 显示 Commited Bytes 170 MB 的组合值
!dumpheap -stat 再次显示最大的消费者大约是 10-25 MB。还有大约 4000 个免费对象,占 38 MB。
最后一个值让我觉得可能OOM是由碎片引起的。但是 38 MB 听起来并不多。
在这一点上我不确定如何继续我如何找到这么多丢失的内存?我怎样才能知道它是否是第三方程序集以及哪一个程序集?
遗憾的是,我无法共享内存转储,因为它包含敏感的客户数据。但我很感激任何建议/提示
c# - 如何确保 C# 中非托管对象数组的正确对齐?
我需要创建一个对象来管理非托管数组的生命周期。
基本结构需要如下。
我不确定的一点是我还需要添加什么以确保数组中对象的对齐方式是应该的?对齐对象是否足够sizeof(T)
?
c# - 非托管内存中的可变字符串可用于托管空间
注意:我的案例是在一个旧 API 的生态系统中,它只适用于字符串,没有现代 .NET 添加。
所以我非常需要没有分配的可变字符串。字符串每 X 毫秒更新一次,因此您可以在几分钟内计算出它可以产生多少垃圾(StringBuilder 甚至根本不接近相关)。我目前的方法是预先分配固定大小的字符串,并通过固定、直接写入字符以及在容量达到时静默掉落或抛出来对其进行变异。
这工作正常。分配的字符串是长期存在的,因此最终 GC 会将其提升到 Gen2 并且固定不会对其造成太大影响,从而最大限度地减少开销。但是有两个主要问题:
- 因为字符串是固定的,我必须用它来填充它,
\0
虽然到目前为止这对所有默认的 NET/MONO 功能和第 3 方的东西都很好,但无法告诉其他东西在 len 为 1024 时会有什么反应,但最后 100 是\0
- 我无法调整它的大小,因为这会导致分配。我可以一次分配一次蓝月亮,但由于字符串是相当动态的,我无法确定它何时会尝试进一步扩展或缩小。我可以使用“仅扩展”方法,这样我只在需要扩展时分配,但是,这有填充开销的缺点(如果字符串扩展为 5k 个字符,但下一个字符串只是 3k - 2k 个字符将被填充额外的周期) 以及额外的内存使用。我不确定 GC 对 mchuge 的感觉如何,通常在 Gen2 中而不是在 LOH 中固定字符串。另一种方法是池可重用字符串对象,但是,这具有更高的内存和 GC 开销 + 查找开销。
由于目标字符串必须存在相当长的时间,我正在考虑通过字节缓冲区将其移动到Unmanaged memory中。这将消除 GC 的负担(固定惩罚开销),并且我可以以比托管堆更低的成本重新调整大小/重新分配。
我很难理解的是- 我怎么可能对分配的非托管缓冲区的特定部分进行切片并将其包装为正常的网络字符串以在托管空间/代码中使用?比如,将它传递给Console.WriteLine
在屏幕上绘制 UI 标签并接受字符串的第 3 方库。这甚至可行吗?
PS 据我所知,NET5 的计划(我认为将在 NET6 中最终确定)您将不再能够改变字符串之类的东西(在运行时被阻止或未定义的故障)。他们的解决方案似乎是我所描述的 POH,具有相同的限制。
c# - 在什么情况下 Marshal.SizeOf 在堆上分配?
这是结构:
这在 Unity 的 mono 2019.4.12-mbe下运行,如果相关,Unity 会生成针对 4.7.1 的项目。Struct 正在通过带有约束的泛型方法传递给 SizeOf where T: struct
,尽管这应该是无关紧要的。
这是单声道的 mscorlib 的 IL Marshal.SizeOf<T>
:
呼叫被转发到外部SizeOf(Type t);
什么可能导致堆分配?我唯一的假设是拳击,但我在这里看不到任何拳击。GetType()
不应该分配
c# - 如何将 IntPtr 转换为结构数组
我有一个 IntPtr,它是一个指向结构数组的指针,我正在尝试将其转换为数组。
我试过了
Marshal.Copy(srcIntPtr, destIntPtrArray, 0, destIntPtrArray.Length);
但是在完成复制之后,我无法将目标数组内部的 IntPtr 转换为所需的结构,而我可以将 srcIntPtr 转换为结构,这当然只会给我第一个索引的数据。看起来在完成复制之后,目标数组包含一堆损坏的 IntPtr
我也试过
这不会引发任何错误,但是我从源 IntPtr 中获取的结构数组的数据不准确。
这是我要转换为的结构
我[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
在结构之上,但删除它并不会破坏我的代码。
提前致谢