作为一个业余爱好项目,我目前正在使用 C# 开发光线追踪器。我试图通过实现 C++ 实现中的一些技巧来实现不错的渲染速度,但遇到了一些麻烦。

光线追踪器渲染的场景中的对象存储在 KdTree 结构中,而树的节点又存储在数组中。我遇到的优化问题是尝试将尽可能多的树节点放入缓存行中。实现此目的的一种方法是让节点仅包含指向左子节点的指针。那么就隐含地表明,右子元素紧跟在数组中的左子元素之后。

节点是结构体,在树构造期间,它们被静态内存管理器类成功放入数组中。当我开始遍历这棵树时,一开始它似乎工作得很好。然后在渲染早期的某个点(每次大约相同的位置),根节点的左子指针突然指向空指针。我得出的结论是,当数组位于堆上时,垃圾收集器已经移动了结构。

我已经尝试了几种方法来将地址固定在内存中,但似乎没有一种方法能够在我需要的整个应用程序生命周期中持续存在。“fixed”关键字似乎只在单个方法调用期间有帮助,并且声明“fixed”数组只能在节点不是的简单类型上完成。有没有好的方法可以做到这一点,还是我在 C# 不适合的东西上走得太远了。

顺便说一句,更改为 C++ 虽然对于高性能程序来说可能是更好的选择,但并不是一个选择。

有帮助吗?

解决方案

首先,如果你正常使用 C#,你不会因为垃圾收集器移动东西而突然获得空引用,因为垃圾收集器也会更新所有引用,所以你不需要担心它移动东西。

您可以将内容固定在内存中,但这可能会导致比它解决的问题更多的问题。一方面,它会阻止垃圾收集器正确压缩内存,并可能以这种方式影响性能。

我从你的帖子中要说的一件事是,使用结构可能不会像你希望的那样帮助提高性能。C# 无法内联任何涉及结构的方法调用,尽管他们在最新的运行时测试版中修复了这个问题,但结构通常表现不佳。

就我个人而言,我认为像这样的 C++ 技巧通常不会很好地移植到 C# 中。你可能要学会稍微放手;还可以有其他更微妙的方法来提高性能;)

其他提示

你的静态内存管理器实际上在做什么?除非它正在执行不安全的操作(P/Invoke、不安全代码),否则您看到的行为是程序中的错误,而不是由于 CLR 的行为造成的。

其次,对于结构之间的链接,“指针”是什么意思?您的字面意思是不安全的 KdTree* 指针吗?不要那样做。相反,使用数组的索引。由于我希望单个树的所有节点都存储在同一个数组中,因此您不需要对该数组进行单独的引用。只需一个索引就可以了。

最后,如果您确实必须使用 KdTree* 指针,那么您的静态内存管理器应该使用例如分配一个大块。Marshal.AllocHGlobal 或其他非托管内存源;它应该将这个大块视为 KdTree 数组(即索引 KdTree* C 风格) 它应该通过碰撞“空闲”指针来从该数组中重新分配节点。

如果您必须调整该数组的大小,那么您当然需要更新所有指针。

这里的基本教训是不安全指针和托管内存会 不是 在“固定”块之外混合,这些块当然具有堆栈帧亲和力(即当函数返回时,固定行为消失)。有一种方法可以使用 GCHandle.Alloc(yourArray, GCHandleType.Pinned) 固定任意对象,例如数组,但您几乎肯定不想走这条路。

如果您更详细地描述您正在做的事情,您会得到更明智的答案。

如果你 真的 如果想要做到这一点,您可以使用 GCHandle.Alloc 方法来指定应固定指针,而不是像固定语句那样在作用域末尾自动释放。

但是,正如其他人所说,这样做会给垃圾收集器带来过度的压力。只创建一个保存一对节点的结构,然后管理一个 NodePairs 数组而不是一个节点数组怎么样?

如果您确实希望对一块内存进行完全非托管访问,那么您可能最好直接从非托管堆分配内存,而不是永久固定托管堆的一部分(这会阻止堆正确地分配内存)。自身紧凑)。一种快速而简单的方法是使用 Marshal.AllocHGlobal 方法。

存储一对数组引用和索引真的禁止吗?

你的静态内存管理器实际上在做什么?除非它正在执行不安全的操作(P/Invoke、不安全代码),否则您看到的行为是程序中的错误,而不是由于 CLR 的行为造成的。

事实上我正在谈论不安全指针。我想要的是类似的东西 Marshal.AllocHGlobal, ,尽管生命周期超过了单个方法调用。经过反思,似乎仅使用索引是正确的解决方案,因为我可能太沉迷于模仿 C++ 代码了。

我从你的帖子中要说的一件事是,使用结构可能不会像你希望的那样帮助提高性能。C# 无法内联任何涉及结构的方法调用,尽管他们在最新的运行时测试版中修复了这个问题,但结构通常表现不佳。

我对此进行了一些研究,发现它已在 .NET 3.5SP1 中修复;我想这就是您所说的运行时测试版。事实上,我现在明白,这种改变使我的渲染速度提高了一倍。现在,结构体被积极地内联,大大提高了它们在 X86 系统上的性能(X64 预先具有更好的结构体性能)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top