是否可以监控.Net的实习池大小?

时间:2017-12-12 11:57:50

标签: c# .net string-interning

我正在维护一个遗留应用程序,它使用字符串来锁定缓存中的值。它是这样的:

object Cache(string key, Func<object> createObjToCache)
{
    object result = Get(key);
    if (result == null)
    {
        string internKey = string.Intern(key);
        lock (internKey) {
            result = Get(key);
            if (result == null)
            {
                result = createObjToCache();
                Add(key, result);
            }
        }
    }
    return result;
}

我对这段代码有两个问题。首先是string.Intern()线程安全吗?两个具有两个相同字符串的独立CPU上的两个线程是否可能返回不同的引用?如果不是那个可能的瓶颈,那就是string.Intern block?

其次我担心这个应用程序可能会使用大量的字符串作为键。我希望能够监视实习池用于存储所有这些字符串的内存量,但我无法在.Net内存上找到性能计数器。在其他地方有人吗?

注意:

我知道这个实现很糟糕。但是,在重新编写他们认为是关键代码之前,我需要向管理层提出这个案例。因此,我可以使用事实和统计数据确切地说它有多糟糕而不是替代解决方案。

Get()和Add()也不在原始代码中。我已经替换了原始代码以保持这个问题的简单。如果使用相同或不同的键调用两次,我们可以假设Add()不会失败。

2 个答案:

答案 0 :(得分:3)

MSDN没有在string.Intern上提及线程安全性,所以你是正确的,如果两个线程为 new <调用Intern,会发生什么情况是非常不明确的/ strong> key在同一时间。我想说“它可能工作正常”,但这不是保证。 没有保证AFAIK。实现是extern,因此窥视实现意味着查看运行时本身。

坦率地说,有很多原因没有这样做,以至于很难对回答这些具体问题感到兴奋。我很想看看某种Dictionary<string,object>ThreadSafeDictionary<string,object>(这里的object只是new object()我可以用来锁定) - 没有string.Intern相关的所有问题。然后我可以:查询大小,b:随意丢弃它,c:有并行隔离容器等。

答案 1 :(得分:2)

  

首先是string.Intern()线程安全吗?

除非有些事情发生了变化(我的信息很老,而且我并不好奇,看看当前的实施情况),是的。然而,这是关于这个想法的唯一好处。

事实上,它并不是一件好事。 string.Intern()全局锁定,这是使其变慢的事情之一。

  

其次,我担心这个应用程序可能会使用大量字符串作为密钥。

如果该缓存永远存在,那么无论您是否实习,这都是一个问题(或者如果内存使用率足够低则不是)。在这种情况下,对正确的潜在问题采取错误的方法进行调查:

  

我希望能够监控实习池用于存储所有这些字符串的内存量,

如果他们没有被实习但仍然永远存在于该缓存中,那么如果你停止实习,你仍然可以与字符串本身的内存量相同,以及额外的内存开销。实习并不是真正的问题。

为什么人们可能想要实习一个密钥有几个原因,而且并非所有这些都是坏的(如果被拦截的字符串在应用程序的整个生命周期中都会定期出现,那么实习甚至可以减少内存使用),但似乎这里的原因是确保锁定的密钥与另一个尝试使用相同字符串的实例相同。

如果Add()的线程安全性不足以保证不同密钥的两次同时插入无法将其置于无效状态(如果{0}},则可能是错误位置的线程安全Add()显然不是线程安全的,然后做出此保证。)

如果缓存是线程安全的,那么这可能是额外的线程安全,没有充分的理由。由于objToCache已经被创建并且比赛将导致一个人被抛弃,所以让他们参加比赛并且在收集一个之前短暂存在两个objToCache可能是好的。如果没有,那么MemoryCache.AddOrGetExistingConcurrentDictionary.GetOrAdd就会比这更好地处理这个问题。