4

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

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

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

4

2 回答 2

5

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

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

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

于 2010-03-17T03:25:26.723 回答
5

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

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

在 Andrew Troelsen 的“Pro C# 2010 和 .Net 平台”中的“理解对象生命周期”一章中对此进行了很好的参考。如果您更喜欢在线参考,请参阅 MSDN 网站实现 Finalize 和 Dispose 以清理非托管资源

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

于 2012-03-20T10:02:04.650 回答