假设您想编写一个处理大型数据集的高性能方法。 为什么开发人员不能开启手动内存管理而不是被迫转向C或C ++?
void Process()
{
unmanaged
{
Byte[] buffer;
while (true)
{
buffer = new Byte[1024000000];
// process
delete buffer;
}
}
}
答案 0 :(得分:13)
因为允许您手动删除内存块,而可能仍然存在对它的引用(并且运行时无法知道没有执行GC循环)会产生悬空指针,从而中断memory safety。 GC语言通常是设计内存安全的。
也就是说,特别是在C#中,你可以做你想做的事情:
void Process()
{
unsafe
{
byte* buffer;
while (true)
{
buffer = Marshal.AllocHGlobal(1024000000);
// process
Marshal.FreeHGlobal(buffer);
}
}
}
请注意,与在C / C ++中一样,您对C#中的原始指针类型有完整的指针算法 - 因此buffer[i]
或buffer+i
是有效的表达式。
答案 1 :(得分:3)
如果您需要高性能和详细控制,也许您应该用C或C ++编写您正在做的事情。并非所有语言都适用于所有事情。
编辑补充:单一语言不会对所有事情都有好处。如果你在所有优秀的编程语言中添加所有有用的功能,那么即使你可以避免不一致,你也会得到一个非常糟糕的混乱,甚至比C ++还要糟糕。
功能不是免费的。如果某种语言具有某项功能,则人们可能会使用该功能。如果不学习新的C#手动内存管理例程,您将无法充分学习C#。编译器团队将以其他有用的编译器功能为代价来实现它。该语言很可能难以像C或C ++一样进行解析,这会导致编译速度变慢。 (作为一个C ++人,当我编译我们的一个C#项目时,我总是很惊讶。编译似乎几乎是即时的。)
功能相互冲突,有时会以意想不到的方式发生冲突。在矩阵计算中,C90不能与Fortran一样好,因为C指针混叠的可能性阻止了一些优化。如果允许使用某种语言的指针算术,则必须接受其后果。
您建议使用C#扩展来允许手动内存管理,并在少数情况下提供有用的内容。这意味着必须以不同的方式分配内存,并且必须有一种方法来从自动管理的内存中告知手动管理的内存。突然之间,你的内存管理变得复杂,程序员有更多机会搞砸了,而内存管理器本身就更复杂了。在一些情况下,您获得了一些重要的性能,以换取更复杂的操作和更慢的内存管理。
在某些时候,我们可能会有一种编程语言几乎可以用于所有目的,从脚本编写到数字运算,但是没有什么比这更接近的流行了。与此同时,我们必须愿意接受仅使用一种语言的局限性,或者学习几种语言并在它们之间切换的挑战。
答案 2 :(得分:0)
在您发布的示例中,为什么不擦除缓冲区并重新使用它?
答案 3 :(得分:0)
.NET垃圾收集器非常善于确定哪些对象不再被引用,并及时释放相关内存。事实上,垃圾收集器有一个特殊的堆(大对象堆),在这个堆中放置像这样的大对象,它被优化以处理它们。
除此之外,不允许显式释放引用只会删除内存泄漏和悬空指针的大量错误,从而导致更安全的代码。
答案 4 :(得分:0)
使用显式内存管理的语言单独释放每个未使用的块可能比让垃圾收集器执行此操作更昂贵,因为GC可以使用复制方案花费时间线性到剩余的块数活着(或最近活动的块数),而不是必须处理每个死区。
答案 5 :(得分:0)
大多数内核都不会让你安排自己的线程。因为99.99 +%的时间你并不真正需要,并且在剩下的时间里暴露这种功能只会诱使你做一些潜在的愚蠢/危险的事情。
如果你真的需要细粒度的内存控制,那就用其他的东西写下那段代码。