C# 当从方法返回并作为参数传递时,结构的预期寿命是多少?

C# 当从方法返回并作为参数传递时,结构的预期寿命是多少?,c#,.net,clr,C#,.net,Clr,我将试着用一个例子来解释这个问题: 我有一个结构: struct RefStruct { public object token; public object item; } 我有一个返回结构的方法: RefStruct createItem() {... } 假设“createItem”生成一个项和一个令牌,其中所述令牌包含“项”和“项”通过WeakReference在内部引用同一令牌时可用的信息 现在,如果我调用此代码(假设“doSomething”处理一个项目并要求令牌处于

我将试着用一个例子来解释这个问题:

我有一个结构:

struct RefStruct
{
   public object token;
   public object item;
}
我有一个返回结构的方法:

RefStruct createItem() {... }
假设“createItem”生成一个项和一个令牌,其中所述令牌包含“项”和“项”通过WeakReference在内部引用同一令牌时可用的信息

现在,如果我调用此代码(假设“doSomething”处理一个项目并要求令牌处于活动状态):

-请注意,调用接收的是“item”,而不是整个结构

是否保证在调用“doSomething”期间,“createItem”返回的结果RefStruct保留在内存中?或者CLR正在丢弃引用,并且现在只引用了项(允许对临时结构进行GCD)


希望这是有道理的;p

结构没有生命周期;持有结构的东西有生命周期。
(虽然装箱结构确实有生命周期)

您的令牌可以立即进行GC,因为它从未被引用

假设“createItem”生成一个项目和一个令牌,其中所述令牌需要保持活动状态(即非GCed)才能使“项目”有效

您的设计从根本上被破坏。如果令牌必须处于活动状态才能使该项有效,则该项应存储对该令牌的引用

修正你的设计。或者将项目的有效性与令牌的生存期分离,或者使项目保留令牌,或者使第三个东西同时保留它们。(然后让第三件事保持活力。)

是否保证在调用“doSomething”期间,“createItem”返回的结果RefStruct保留在内存中

绝对不是。垃圾收集器不仅在调用DoSomething之前,而且实际上在CreateItem返回之前,都有权收集令牌。垃圾收集器可以任意地展望未来,并预测程序的未来行为。如果它可以通过分析确定从未访问过令牌对象,则允许它在创建令牌对象后立即释放它

在CLR的任何实现中,它是否真的这样做是一个实现细节,可能会发生变化

如果我将“CreateItem”的结果存储到临时结构中,并将“item”属性传递给“doSomething”,那么优化器是否仍然允许提前释放令牌

对。jit编译器完全有权确定现在升级为局部变量的结构的令牌字段永远不会被访问;它完全有权对令牌引用进行垃圾收集

结构存储本身不会提前回收;例如,您可以稍后写入本地存储的令牌字段部分。但是令牌字段引用的对象的内存可以随时回收

在“令牌”成员上使用volatile会改变这一点吗

否。易失性字段在写入和读取时具有获取和释放语义;这与能量场的寿命毫无关系

你能解释一下为什么你会认为让这个字段不稳定会改变它的寿命吗?我一直很想知道人们为什么相信奇怪的事情

我想保证,只要我持有代币,它就不会被GCD,以避免在“doSomething”操作期间发生GC

现在我们来谈谈实际问题。到目前为止,你一直在问有关钻机电机如何工作的问题,而不是问你想钻什么样的孔。如果问题是“我如何让这个死东西活着?”答案很简单打电话。就是为了这个

正如文件明确指出的那样:

KeepAlive方法的目的是确保存在对有可能被垃圾收集器过早回收的对象的引用

现在,一个合理的问题是“但是如果代币有被收集的危险,那么怎么可能有人使用它来提高物品的效率?”您在下面的评论中回答这个问题:

这是缓存系统的一部分,由于strct中的“token”是强引用,因此还有其他weakreference,虽然未收集到token,但已知缓存项是必需的,不应从缓存中删除

您让垃圾收集器负责强制执行缓存策略。垃圾收集器的设计不适合您的场景;垃圾收集器的设计目的是为了在通用编程语言中具有良好的内存管理性能

在我将由一群人设计的终身管理引擎用于解决他们的一般问题之前,我会仔细考虑,以确定一个可能完全不同的问题空间的策略。您提出这类问题的事实表明,您需要构建自己的缓存策略实施代码,而不是依赖GC以不符合您喜欢的方式为您执行

超级猫问:


如果用类替换RefStruct,不会出现完全相同的问题吗

对。如果你这样做,比如说:

Tuple<object, object> holder = CreateItem(...); 
DoSomething(holder.Item1);
Tuple holder=CreateItem(…);
剂量计(持有人项目1);

然后,GC完全有权确定“holder”已死亡,因此holder.Item2已死亡,此时CreateItem已完成执行。正如我所说,你必须让“持有者”——第三件事——活着。允许GC确定哪些仍然存在。

否,
RefStruct
可以立即进行GCed。即使这样做:

var rs = createItem();
doSomething(rs.item);
不会保证令牌保持活动状态

可以考虑执行<代码> IDISPOLITION/C

var rs = createItem();
doSomething(rs.item);
class RefStruct : IDisposable
{
   public object token;
   public object item;

   public void Dispose() 
   { 
       Dispose(true);
       GC.SuppressFinalize(this);
   }

   protected virtual void Dispose(bool disposing)
   {
        if (disposing)
        {
            token = null; // not necessary technically
        }
    }
}
using (var rs = createItem())
{
    doSomething(rs.Item);
}