为什么托管语言不提供手动删除对象的功能?

发布于 2024-08-14 04:19:57 字数 302 浏览 2 评论 0原文

假设您想编写一个处理大型数据集的高性能方法。 为什么开发人员不应该有能力打开手动内存管理,而不是被迫转向 C 或 C++?

void Process()
{
    unmanaged
    {
        Byte[] buffer;
        while (true)
        {
            buffer = new Byte[1024000000];

            // process

            delete buffer;
        } 
    }   
}

Lets say you want to write a high performance method which processes a large data set.
Why shouldn't developers have the ability to turn on manual memory management instead of being forced to move to C or C++?

void Process()
{
    unmanaged
    {
        Byte[] buffer;
        while (true)
        {
            buffer = new Byte[1024000000];

            // process

            delete buffer;
        } 
    }   
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

嘴硬脾气大 2024-08-21 04:19:58

因为允许您手动删除内存块,同时可能仍然存在对它的引用(并且运行时无法知道不进行 GC 循环)可能会产生悬空指针,从而破坏 内存安全。 GC 语言通常在设计上是内存安全的。

也就是说,特别是在 C# 中,您已经可以做您想做的事情了:

void Process()
{
    unsafe
    {
        byte* buffer;
        while (true)
        {
            buffer = Marshal.AllocHGlobal(1024000000);

            // process

            Marshal.FreeHGlobal(buffer);
        } 
    }   
}

请注意,与 C/C++ 中一样,您对 C# 中的原始指针类型拥有完整的指针算术 - 所以 buffer[i]buffer+i 是有效的表达式。

Because allowing you to manually delete a memory block while there may still be references to it (and the runtime has no way of knowing that without doing a GC cycle) can produce dangling pointers, and thus break memory safety. GC languages are generally memory-safe by design.

That said, in C#, in particular, you can do what you want already:

void Process()
{
    unsafe
    {
        byte* buffer;
        while (true)
        {
            buffer = Marshal.AllocHGlobal(1024000000);

            // process

            Marshal.FreeHGlobal(buffer);
        } 
    }   
}

Note that, as in C/C++, you have full pointer arithmetic for raw pointer types in C# - so buffer[i] or buffer+i are valid expressions.

自此以后,行同陌路 2024-08-21 04:19:58

如果您需要高性能和详细控制,也许您应该用 C 或 C++ 编写您正在做的事情。并非所有语言都适合所有事情。

编辑添加:单一语言并不适合所有事情。如果您将所有优秀编程语言中的所有有用功能相加,您将得到一个非常大的混乱,比 C++ 糟糕得多,即使您可以避免不一致。

功能不是免费的。如果一种语言有某种特性,人们就可能会使用它。如果不学习新的 C# 手动内存管理例程,您就无法学好 C#。编译器团队将以牺牲其他有用的编译器功能为代价来实现它。该语言可能会像 C 或 C++ 一样难以解析,从而导致编译速度缓慢。 (作为一名 C++ 人员,当我编译一个 C# 项目时,我总是感到惊讶。编译似乎几乎是瞬时的。)

功能彼此冲突,有时会以意想不到的方式发生冲突。 C90 在矩阵计算方面不如 Fortran,因为 C 指针别名的可能性会妨碍某些优化。如果你允许某种语言中的指针运算,你就必须接受它的后果。

您建议使用 C# 扩展来允许手动内存管理,并且在某些情况下这会很有用。这意味着必须以不同的方式分配内存,并且必须有一种方法来区分手动管理的内存和自动管理的内存。突然之间,内存管理变得复杂起来,程序员搞砸的机会就更多了,而且内存管理器本身也变得更加复杂。您获得了一些在某些情况下很重要的性能,但在所有情况下却换来了更多的复杂性和更慢的内存管理。

也许有一天,我们会拥有一种几乎适用于所有用途的编程语言,从脚本编写到数字运算,但没有任何流行的语言可以与之相媲美。与此同时,我们必须愿意接受仅使用一种语言的局限性,或者学习多种语言并在它们之间切换的挑战。

If you need high performance and detailed control, maybe you should write what you're doing in C or C++. Not all languages are good for all things.

Edited to add: A single language is not going to be good for all things. If you add up all the useful features in all the good programming languages, you're going to get a really big mess, far worse than C++, even if you can avoid inconsistency.

Features aren't free. If a language has a feature, people are likely to use it. You won't be able to learn C# well enough without learning the new C# manual memory management routines. Compiler teams are going to implement it, at the cost of other compiler features that are useful. The language is likely to become difficult to parse like C or C++, and that leads to slow compilation. (As a C++ guy, I'm always amazed when I compile one of our C# projects. Compilation seems almost instantaneous.)

Features conflict with each other, sometimes in unexpected ways. C90 can't do as well as Fortran at matrix calculations, since the possibility that C pointers are aliased prevents some optimizations. If you allow pointer arithmetic in a language, you have to accept its consequences.

You're suggesting a C# extension to allow manual memory management, and in a few cases that would be useful. That would mean that memory would have to be allocated in separate ways, and there would have to be a way to tell manually managed memory from automatically managed memory. Suddenly, you've complicated memory management, there's more chance for a programmer to screw up, and the memory manager itself is more complicated. You're gaining a little performance that matters in a few cases in exchange for more complication and slower memory management in all cases.

It may be that at some time we'll have a programming language that's good for almost all purposes, from scripting to number crunching, but there's nothing popular that's anywhere near that. In the meantime, we have to be willing to accept the limitations of using only one language, or the challenge of learning several and switching between them.

未央 2024-08-21 04:19:58

在您发布的示例中,为什么不直接擦除缓冲区并重新使用它呢?

In the example you posted, why not just erase the buffer and re-use it?

℡Ms空城旧梦 2024-08-21 04:19:58

.NET 垃圾收集器非常擅长找出哪些对象不再被引用,并及时释放关联的内存。事实上,垃圾收集器有一个特殊的堆(大对象堆),它在其中放置像这样的大对象,并对其进行了优化处理。

最重要的是,不允许显式释放引用可以简单地消除大量内存泄漏和悬空指针的错误,从而使代码更加安全。

The .NET garbage collector is very very good at working out which objects aren't referenced anymore and freeing the associated memory in a timely manner. In fact, the garbage collector has a special heap (the large object heap) in which it puts large objects like this, that is optimized to deal with them.

On top of this, not allowing references to be explicitly freed simply removes a whole host of bugs with memory leaks and dangling pointers, that leads to much safer code.

初心 2024-08-21 04:19:58

使用具有显式内存管理的语言单独释放每个未使用的块可能比让垃圾收集器执行此操作更昂贵,因为 GC 有可能使用复制方案来花费与剩余活动块数成线性关系的时间(或最近存活的块的数量),而不必处理每个死块。

Freeing each unused block individually as done in a language with explicit memory management can be more expensive than letting a Garbage Collector do it, because the GC has the possibility to use copying schemes to spend a time linear to the number of blocks left alive (or the number of recent blocks left alive) instead of having to handle each dead block.

一梦等七年七年为一梦 2024-08-21 04:19:58

这与大多数内核不允许您调度自己的线程的原因相同。因为 99.99+% 的时间你并不真正需要这样做,而在其余时间暴露该功能只会诱使你做一些可能愚蠢/危险的事情。

如果您确实需要细粒度的内存控制,请将该部分代码写在其他内容中。

The same reason most kernels won't let you schedule your own threads. Because 99.99+% of time you don't really need to, and exposing that functionality the rest of the time will only tempt you to do something potentially stupid/dangerous.

If you really need fine grain memory control, write that section of code in something else.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文