0

我的任务是更新旧的 32 位 C# 应用程序,以支持将 4K/UHD 图像(jpg、tiff 等)转换为 YUV 图像以进行进一步处理。我们完成转换 SD/HD 内容的方法是使用 DLL 来调用开源工具 FFmpeg 来执行操作。这是通过执行以下操作来完成的:

  1. C# 应用程序将图像文件传递给 DLL
  2. 然后,DLL 分配捕获新转换图像所需的内存(每帧字节数 => 1080p=8.2mb,2160p=33.2mb)
  3. 然后 DLL 通过传入指向文件的指针和分配的内存缓冲区来调用第 3 方工具
  4. 一旦函数调用返回,我们将转换后的图像保存到文件中
  5. 清理(​​关闭文件、释放内存等)
  6. 无论成功与否,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# 更大,但不是千兆字节。 系统资源 任务管理器

最后说明:

  1. 我不愿意将 32 位 C# 应用程序转换为 64 位。我知道它很旧,应该更新,但目前要做的工作太大了。此外,我相信已经证明这不是 32 位问题,因为我的测试应用程序有效。
  2. 我愿意在 C# 应用程序中分配内存并将其传递到 DLL 以供它使用,而不是在其中分配。如果我不能按设计解决它,那是我的备用计划。
  3. 我不相信我在 DLL 中有内存泄漏,因为我使用 Resharper dotMemory 对其进行了分析
  4. 如果您帮不上忙,感谢您愿意为实现这一目标而敞开心扉!
4

1 回答 1

0

我发现的最佳解决方案是将内存分配从函数中移动到定义全局块。我没有为我转换的每个图像分配/取消分配内存块,而是将其更改为使用/重用全局块(设置为可能的最大大小)。当然,我知道如果我在施工时没有连续的块,我仍然可以获得 bad_alloc。但是,我相信此更改对我有用,因为下次我需要它时不会丢失我的 33MB 连续块。我对正在发生的事情的猜测——Windows 内存管理器在我释放它之后占用了我的连续块,最终使我处于下一次需要 33MB 块的情况下,没有任何连续的东西。希望这个解释对将来的人有所帮助。

于 2021-01-09T00:28:01.533 回答