Java和C#中的内存管理有何不同?

Dav*_*one 4 c# java memory-management buffer-overflow

我正在阅读2010年CWE/SANS排名前25位最危险的编程错误,其中一个条目是缓冲区复制而不检查输入大小.它建议使用具有功能的语言来预防或缓解此问题,并说:

例如,许多执行自己的内存管理的语言(如Java和Perl)不会受到缓冲区溢出的影响.其他语言(如Ada和C#)通常提供溢出保护,但程序员可以禁用保护.

我不知道Java和C#在内存管理方面有任何有意义的不同.Java如何不受缓冲区溢出的影响,而C#只能防止溢出?如何在C#中禁用这种保护?

Mit*_*eat 5

java不支持原始指针(严格来说它不支持指针运算).

在C#中,您可以使用不安全的代码和指针以及非托管内存,这会使缓冲区溢出成为可能.请参阅unsafe关键字.

为了保持类型安全性和安全性,默认情况下C#不支持指针算法.但是,通过使用unsafe关键字,您可以定义可以使用指针的不安全上下文.有关指针的更多信息,请参阅指针类型主题.


Zac*_*sen 5

好的答案。我想补充一点,Java 取决于堆栈或堆内存位置的使用。C# 也是如此。使用原始指针的想法是对 C# 的补充,源自 C 代码背景。尽管 C# 和 C/C++ 不是同一种代码语言,但它们确实共享一些共性语义。使用“不安全”代码的想法可以让您避免在堆上保留大型对象,其中每个运行时实例的内存限制为 2GB 左右(对于每个 CLR 的 C#,每个 JVM 实例的 Java),而不会因垃圾收集而导致性能急剧下降。在某些情况下,您可以使用 C# 的能力来利用不安全或手动管理的内存指针来解决这样一个事实:没有那么多第三方工具可以解决堆外缓存等问题。

我要提醒您的是,如果您确实使用不安全的代码,请务必熟悉“一次性类型”和“终结器”。这可能是一种相当高级的实践,不正确处理对象的后果与 C 代码相同……可怕的内存泄漏。后果是你的应用程序内存不足并且它崩溃了(不好)。这就是为什么 C# 默认情况下不允许这样做,并且您需要使用“unsafe”关键字覆盖手动控制指针的任何使用。这确保了任何手动处理的内存都是有意的。处理“不安全”关键字时,请戴上 C 代码帽子。

Andrew Troelsen 的“Pro C# 2010 和 .Net Platform”中的“Understanding Object Lifetime”一章对此有很好的参考。如果您更喜欢在线参考,请参阅 MSDN 网站实现 Finalize 和 Dispose 以清理非托管资源

最后一点 - 非托管内存在对象的终结器部分中释放(~ObjectName(){...})。这些模式确实会增加性能开销,因此如果您正在处理较低延迟的场景,那么保持对象轻量可能是最好的选择。如果您正在处理人类反应,那么您应该在绝对必要时考虑这一点。