缓存从反射获得的昂贵数据的最佳方法是什么?例如,大多数快速序列化程序都会缓存此类信息,因此无需在每次遇到相同类型时进行反映.他们甚至可以生成一个动态方法,从类型中查找.
传统上我使用了普通的静态字典.例如:
private static ConcurrentDictionary<Type, Action<object>> cache;
public static DoSomething(object o)
{
Action<object> action;
if(cache.TryGetValue(o.GetType(), out action)) //Simple lookup, fast!
{
action(o);
}
else
{
// Do reflection to get the action
// slow
}
}
Run Code Online (Sandbox Code Playgroud)
这会泄漏一点内存,但是因为它只对每种类型和类型执行一次,只要AppDomain我不认为这是一个问题.
但是现在.net 4引入了用于动态类型生成的可收集组件.如果我曾经使用过可DoSomething收集组件中声明的对象,那么组件将不会被卸载.哎哟.
那么在.net 4中缓存每种类型信息的最佳方法是什么?没有遇到这个问题?我能想到的最简单的解决方案是:
private static ConcurrentDictionary<WeakReference, TCachedData> cache.
Run Code Online (Sandbox Code Playgroud)
但IEqualityComparer<T>我必须使用它会表现得非常奇怪,也可能违反合同.我不确定查找的速度有多快.
另一个想法是使用到期超时.可能是最简单的解决方案,但感觉有点不雅.
在类型作为通用参数提供的情况下,我可以使用嵌套的泛型类,它不应该遇到这个问题.但是如果在变量中提供类型,则它不起作用.
class MyReflection
{
internal Cache<T>
{
internal static TData data;
}
void DoSomething<T>()
{
DoSomethingWithData(Cache<T>.data);
//Obviously simplified, should have …Run Code Online (Sandbox Code Playgroud) 我有一些WCF Web服务的问题(一些转储,内存泄漏等),我运行一个profillng工具(ANTS内存配置文件).
只是为了发现即使处理结束(我运行特定测试然后停止),第2代也是Web服务内存的25%.我追踪到这个内存,发现我有一个字典对象,里面有(null,null)项,带有-1个哈希码.
Web服务的工作流意味着在特定处理期间添加项目然后从字典中删除(只是简单Add和Remove).没有大碍.但似乎在删除所有项目后,字典中充满了(null,null)KeyValuePairs.事实上,成千上万的它们占据了很大一部分内存并最终发生了溢出,相应的强制应用程序池回收和DW20.exe获得了它可以获得的所有CPU周期.
实际上是字典Dictionary<SomeKeyType, IEnumerable<KeyValuePair<SomeOtherKeyType, SomeCustomType>>>(System.OutOfMemoryException,因为大字典)所以我已经检查过是否存在某种引用.
字典包含在一个静态对象中(通过处理使其可以访问不同的处理线程)所以从这个问题和更多(静态成员是否得到垃圾收集?)我理解为什么该字典在第2代.但这是那些原因(null,null)?即使我从字典中删除项目,内存中也会总是占用一些东西?
这不是像这个问题中的速度问题从C#中的大型数据结构中释放内存.似乎记忆永远不会被回收.
有什么我可以做的事实上从字典中删除项目,而不是继续填充(null,null)对吗?还有什么我需要检查的吗?
public class MyClass {
private static MyClass heldInstance;
public MyClass() {
heldInstance = this;
}
}
Run Code Online (Sandbox Code Playgroud)
假设MyClass的一个实例没有以任何其他方式生根,那么这里的私有静态引用是否会阻止它被垃圾收集?
我SomeSingleton在C#中有一些类(如果重要,则为.NET 3.5)和代码:
foo()
{
...
SomeSingleton.Instance.DoSomething();
...
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:垃圾收集器什么时候会收集这个Singleton对象?
ps:SomeSingleton的代码:
private static SomeSingleton s_Instance = null;
public static SomeSingleton Instance
{
get
{
if (s_Instance == null)
{
lock (s_InstanceLock)
{
if (s_Instance == null)
{
s_Instance = new SomeSingleton();
}
}
}
return s_Instance;
}
}
Run Code Online (Sandbox Code Playgroud)
感谢帮助!
编辑(附说明):
在Widnows服务中我有代码:
...
FirstSingleton.Instance.DoSomething();
...
public class FirstSingleton
{
(Instance part the same as in SomeSingleton)
public void DoSomething()
{
SomeSingleton.Instance.DoSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
我想要实现的目标:我不关心FirstSingleton会发生什么,但SomeSingleton首先使用它启动Timer,所以我需要SomeSingleton存在(所以定时器可以在每个时间段运行新线程),只要我的服务是运行.
正如我从你的答案中理解的那样,所有这一切都会发生,因为对我的FirstSingleton和SomeSingleton的引用是静态的,并且在服务停止之前GC不会收集单身人士,我是对的吗?:)
该DoSomething()方法会导致内存泄漏吗?
public static class AppContext
{
public static int ApplicationStateId {get; set}
...
}
public class MyService
{
public void DoSomething()
{
....
if(AppContext.ApplicationStateId == 1)
{
//do something
}
}
}
Run Code Online (Sandbox Code Playgroud)
var service = new MyService();
service.DoSomething();
Run Code Online (Sandbox Code Playgroud)
这意味着静态变量及其引用的所有内容永远不会被垃圾收集。
Michael在 .NET 中导致内存泄漏的 8 种方法中说道。