我正在阅读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#中禁用这种保护?
答案 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(){...})。这些模式确实会增加性能开销,因此如果您处理较低延迟的情况,最好通过保持对象轻松来实现。如果您正在处理人类反应,那么您应该在绝对必要的情况下考虑这一点。