拳击会在 .NET 中产生垃圾吗?

发布于 2024-08-20 13:37:13 字数 576 浏览 10 评论 0原文

我想知道在对象中装箱值类型是否是一种特殊情况,或者在删除对它的任何引用后,.NET 构造的“盒子”是否会变成垃圾(GC 必须收集的垃圾)。

例如, StringBuilder.AppendFormat() 具有以下重载:

StringBuilder.AppendFormat(string format, object arg0);
StringBuilder.AppendFormat(string format, object arg0, object arg1);
StringBuilder.AppendFormat(string format, object arg0, object arg1, object arg2);
StringBuilder.AppendFormat(string format, params object[] args);

对具有 3 个或更少参数的调用进行这些额外重载可能表明装箱确实是一种特殊情况(或者从性能的角度来看,它值得避免)数组构造)。

理论上,使用普通的旧引用计数(可能带有一组可重用框)将是一种有效的实现,因为不能有从一个框到另一个框的引用,只能从 .NET 对象到一个框的引用。

I'm wondering whether boxing a value type in an object is a special case or whether the "box" constructed by .NET becomes garbage (that the GC has to collect) after any references to it are dropped.

For example, StringBuilder.AppendFormat() has these overloads:

StringBuilder.AppendFormat(string format, object arg0);
StringBuilder.AppendFormat(string format, object arg0, object arg1);
StringBuilder.AppendFormat(string format, object arg0, object arg1, object arg2);
StringBuilder.AppendFormat(string format, params object[] args);

Having those additional overloads for calls with 3 or fewer arguments might indicate that boxing indeed is a special case (or that it pays off, from a performance point-of-view, to avoid array construction).

Theoretically, using plain old reference counting, possibly with a pool of reusable boxes would be a valid implementation because there can be no references from one box to another, only from .NET objects to a box.

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

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

发布评论

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

评论(3

美胚控场 2024-08-27 13:37:13

首先,澄清一下:创建对象引用数组不是装箱。 “拳击”是一个在 .NET 中具有非常具体含义的术语,我认为值得坚持使用它。

装箱确实会产生垃圾,或者更确切地说,每次装箱时,它都会创建一个新对象,该对象最终可能会变成垃圾。 (它不必成为垃圾 - 您可能在应用程序的剩余生命周期中拥有对该对象的引用;这种情况非常罕见。)

但是,您可以有一个用于装箱目的的缓存。事实上,Java 确实适合少数人。如果你写:

Integer x = 5;
Integer y = 5;
System.out.println(x == y); // Reference comparison

那么就保证打印true

但是,这只是一组固定类型的小型缓存 - 它不是通用缓存。您需要平衡通用缓存与弱引用的痛苦(不是引用计数 - .NET 中的 GC 机制只是引用计数,并且您无法真正引入该对于装箱值来说)几乎肯定会比装箱产生垃圾的小成本对性能造成的影响更大。

.NET可以采用与 Java 相同的方法,并对某些类型的某些值进行装箱,但我不确定是否值得额外的概念性包袱——特别是当平台支持自定义值类型时(Java 不支持)。

值得注意的是,自 .NET 2.0 以来,拳击比以前少了一些。这种情况在数据绑定和反射中经常发生,但现在在普通的旧数据操作中不太常见。

First off, just to clarify: creating an array of object references is not boxing. "Boxing" is a term with a very specific meaning in .NET, and I think it's worth sticking to it.

Boxing does create garbage - or rather, each time you box, it creates a new object which is likely to eventually become garbage. (It doesn't have to become garbage - you might have a reference to that object for the rest of the app's lifetime; it's just pretty rare.)

However, you could have a cache for boxing purposes. Indeed, Java does for small numbers. If you write:

Integer x = 5;
Integer y = 5;
System.out.println(x == y); // Reference comparison

then that's guaranteed to print true.

However, that's just a small cache for a fixed set of types - it's not a general purpose cache. You need to balance the pain of having a general cache with weak references (not reference counting - the GC mechanism in .NET just isn't reference counted, and you couldn't really introduce that just for boxed values) would almost certainly hurt performance more than the small cost of boxing creating garbage.

.NET could have taken the same approach as Java and boxed some values of some types, but I'm not sure it's worth the extra conceptual baggage - especially when the platform supports custom value types (which Java doesn't).

It's probably worth noting that since .NET 2.0, boxing is somewhat rarer than it used to be. It happens a fair amount in data binding and reflection, but it's less common in plain old data manipulation now.

给妤﹃绝世温柔 2024-08-27 13:37:13

装箱的值类型成为堆上的对象,并且像任何其他对象一样,一旦不再被引用,就必须(并且将会)被垃圾收集。

创建具有 3 个或更少参数的方法重载(正如您所观察到的)是为了避免数组构造,并且是一种性能优化。请参阅“考虑为对性能极其敏感的 API 中使用少量参数的调用提供特殊重载和代码路径”,网址为 具有可变数量参数的成员

但是,创建数组与装箱值类型有本质上的不同。调用 StringBuilder.AppendFormat 的任何重载都将始终将值类型的参数装箱,因为无论是否创建数组,参数的类型都为 object。有关装箱的详细说明,请参阅 .NET 中的“装箱和拆箱”:类型基本原理

A value type that is boxed becomes an object on the heap, and like any other object must (and will) be garbage collected once it is no longer referenced.

Creating method overloads with 3 or fewer arguments is (as you observe) to avoid array construction, and is a performance optimization. See "Consider providing special overloads and code paths for calls with a small number of arguments in extremely performance-sensitive APIs" at Members with a Variable Number of Parameters.

However, creating an array is fundamentally different than boxing a value type. Calling any overload of StringBuilder.AppendFormat will always box arguments that are value types, because the parameter is typed as object, whether or not an array is created. For a detailed explanation of boxing, see "Boxing and Unboxing" at .NET: Type Fundamentals.

泅渡 2024-08-27 13:37:13

你问错了问题。

您指向的重载是为了优化直接参数调用。这意味着编译器会将变量放入 arg_0、arg_1、arg_2、arg_3 中,可能不止这些,但 IL 仅将这些变量作为快速访问。其余的无论如何都会通过堆栈,因此并不比参数类型的函数调用更有效。

对于参数类型函数调用,它实际上在场景后面创建一个数组并将其作为 arg_1 发送到函数(在本例中,arg_0 由字符串占用)。

You are asking the wrong question.

The overloads that you are pointing to is to optimize for direct parameter calling. Meaning the compiler will put the variables into arg_0, arg_1, arg_2, arg_3, it is possible to have more than that, but the IL only has these as quick access. The rest goes through the stack anyway, and is therefore not much more effecient than the param typed function call.

For the param typed function call, it actually makes an array behind the scenenes and send that to the function as arg_1 (in this case, where arg_0 is taken up by the string).

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