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

时间:2010-03-17 03:22:42

标签: c# java memory-management buffer-overflow

我正在阅读2010 CWE/SANS Top 25 Most Dangerous Programming Errors,其中一个条目是Buffer Copy without Checking Size of Input。它建议使用具有功能的语言来预防或缓解此问题,并说:

  

例如,许多语言   执行自己的内存管理,   例如Java和Perl,不是主题   缓冲溢出。其他语言,   例如Ada和C#,通常提供   溢出保护,但   保护可以被禁用   程序员。

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

2 个答案:

答案 0 :(得分:5)

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

在C#中,您可以使用unsafe code and pointers和非托管内存,这可以使缓冲区溢出成为可能。请参阅unsafe关键字。

  

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

答案 1 :(得分:4)

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

我要提醒您,如果您使用不安全的代码,请务必熟悉“一次性类型”和“终结器”。这可能是一个相当先进的做法,并且没有正确处理对象的后果与C代码相同......可怕的MEMORY LEAK。你的应用程序内存不足会导致内存不足(不好)。这就是为什么C#默认不允许它,并且您需要使用“unsafe”关键字覆盖任何手动控制指针的使用。这确保了任何手动处理的内存都是有意的。在处理“不安全”关键字时,请戴上您的C代码帽。

对此的一个很好的参考是Andrew Troelsen撰写的“Pro C#2010和.Net平台”中的“理解对象生命周期”一章。如果您更喜欢在线参考,请参阅MSDN网站Implementing Finalize and Dispose to Clean Up Unmanaged Resources

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