【问题标题】:How to prevent StackOverflowException when reusing a callback in a callback?在回调中重用回调时如何防止 StackOverflowException?
【发布时间】:2015-05-21 10:30:54
【问题描述】:

我有一些依赖于 HttpContext.Cache 的代码,如果满足某个条件,我希望它在其中重新缓存某些内容。但是,这会引入潜在的堆栈溢出,我不确定这里的合适方法是什么。

看这段代码sn-p:

void OnCacheItemRemoved( string key, object value, CacheItemRemovedReason reason )
    {
        var c = value as RequestCounter;
        if ( c == null )
            return;

        if ( .. Some logic that might be true .. )
        {
            Cache.Insert( key, c, null, DateTime.UtcNow.AddSeconds( timeWindow ),
                Cache.NoSlidingExpiration, CacheItemPriority.Low, OnCacheItemRemoved );
        }
    }

在调试时,堆栈跟踪似乎没有建立,但在现实生活中,它确实存在。这是否取决于调用回调的方式(例如,是否会因某种原因立即释放缓存)?

另外,最好的解决方案是什么?传入一个带有重复代码的委托(可能将除 Cache.Insert 之外的逻辑移动到一个通用方法)?我仍然担心它会建立一个堆栈,我不确定我有什么选择。

有什么建议吗?

【问题讨论】:

  • 我希望问题不会变成那样,即使没有 StackOverflowException,你也可以有一个无限循环 OnCacheItemRemoved->Add, removed because full, OnCacheItemRemoved->Add
  • 你能登录CacheItemRemovedReason reason吗?
  • 您是否关心回调堆栈的构建?
  • @xanatos 好点,我无法在我的开发环境中复制它,但记录原因是一个好的开始。
  • @TravisJ 好吧,不仅担心,而且它在生产中抛出 StackOverflowException 是一个事实。我只是不知道为什么这在我的开发环境中无法追踪。

标签: c# asp.net .net recursion


【解决方案1】:

根据我的观察添加答案:

在这种情况下防止 StackOverflowException 的一种解决方案

    void OnCacheItemRemoved( string key, object value, CacheItemRemovedReason reason )
    {

        if ( reason != CacheItemRemovedReason.Expired )
        {
            return;
        }

至少,这可以防止堆栈溢出。 stackoverflow 异常原因背后的理论似乎是当缓存项被替换(或被插入重新缓存)时调用了回调。两个并行请求,将尝试缓存相同的项目,将创建一个竞争条件,其中第一个缓存的项目将被第二个请求过期,从而调用回调,该回调又将再次插入它,调用第二个回调并导致在无限失效中,原因是“已删除”。似乎这场比赛会建立调用堆栈,而到期线程则不会。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-15
    • 2015-04-23
    • 1970-01-01
    • 2011-09-20
    • 2017-05-11
    • 2021-10-19
    • 2011-11-18
    • 1970-01-01
    相关资源
    最近更新 更多