c# - 垃圾收集器在 WeakReference 中删除(收集)对象的优先级是多少?
问题描述
我是 C# 新手,我正在学习垃圾收集器,我正在学习弱参考课程
这里是在 msdn 中使用弱引用的示例
这个例子 :
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// Create the cache.
int cacheSize = 50;
Random r = new Random();
Cache c = new Cache(cacheSize);
string DataName = "";
GC.Collect(0);
// Randomly access objects in the cache.
for (int i = 0; i < c.Count; i++) {
int index = r.Next(c.Count);
// Access the object by getting a property value.
DataName = c[index].Name;
}
// Show results.
double regenPercent = c.RegenerationCount/(double)c.Count;
Console.WriteLine("Cache size: {0}, Regenerated: {1:P2}%", c.Count,
regenPercent);
}
public class Cache
{
// Dictionary to contain the cache.
static Dictionary<int, WeakReference> _cache;
// Track the number of times an object is regenerated.
int regenCount = 0;
public Cache(int count)
{
_cache = new Dictionary<int, WeakReference>();
// Add objects with a short weak reference to the cache.
for (int i = 0; i < count; i++) {
_cache.Add(i, new WeakReference(new Data(i), false));
}
}
// Number of items in the cache.
public int Count
{
get { return _cache.Count; }
}
// Number of times an object needs to be regenerated.
public int RegenerationCount
{
get { return regenCount; }
}
// Retrieve a data object from the cache.
public Data this[int index]
{
get {
Data d = _cache[index].Target as Data;
if (d == null) {
// If the object was reclaimed, generate a new one.
Console.WriteLine("Regenerate object at {0}: Yes", index);
d = new Data(index);
_cache[index].Target = d;
regenCount++;
}
else {
// Object was obtained with the weak reference.
Console.WriteLine("Regenerate object at {0}: No", index);
}
return d;
}
}
}
// This class creates byte arrays to simulate data.
public class Data
{
private byte[] _data;
private string _name;
public Data(int size)
{
_data = new byte[size * 1024];
_name = size.ToString();
}
// Simple property.
public string Name
{
get { return _name; }
}
}
// Example of the last lines of the output:
//
// ...
// Regenerate object at 36: Yes
// Regenerate object at 8: Yes
// Regenerate object at 21: Yes
// Regenerate object at 4: Yes
// Regenerate object at 38: No
// Regenerate object at 7: Yes
// Regenerate object at 2: Yes
// Regenerate object at 43: Yes
// Regenerate object at 38: No
// Cache size: 50, Regenerated: 94%
垃圾收集器在 WeakReference 中删除(收集)对象的优先级是多少?
为什么 GC 在缓存中选择这个对象来删除 94% 并保留 6%
解决方案
WeakReferences 允许对引用对象进行垃圾收集。垃圾收集器将收集它正在收集的一代中的所有可收集对象。
我的猜测是,当调用发生时,某些对象已被提升为 gen 1/2 GC.Collect(0)
。如果你用我替换它,GC.Collect(2)
我希望没有任何对象活着。
WeakReference 通常不是缓存的好主意。我避免它,并在我想缓存某些东西时使用强引用。通常结合某种方式来估计内存使用量才能设置内存上限。现在内存通常很充足,因此减少内存使用的重要性有限。
还有内存池的相关概念,这可以用于在使用大内存缓冲区时减少第 2 代 GC。
编辑:
稍微简化了您的示例:
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
GC.TryStartNoGCRegion(10000000);
var cache = new Cache(50);
Console.Write("Objects alive Before: " + cache.CountObjectsAlive());
GC.EndNoGCRegion();
GC.Collect(2, GCCollectionMode.Forced);
Console.WriteLine("\tAfter : " + cache.CountObjectsAlive());
}
Console.ReadKey();
}
public class Cache
{
// Dictionary to contain the cache.
Dictionary<int, WeakReference> _cache = new Dictionary<int, WeakReference>();
public Cache(int count)
{
// Add objects with a short weak reference to the cache.
for (int i = 0; i < count; i++)
{
_cache.Add(i, new WeakReference(new byte[i * 1024], false));
}
}
public int CountObjectsAlive() => _cache.Values.Count(v => v.Target != null);
}
这始终在 GC 之前使 50 个对象处于活动状态,在 GC 之后使 0 个对象处于活动状态。TryStartNoGCRegion
请注意在创建对象时防止 GC 运行的用法。如果我更改程序以确保某些对象被提升到 gen 1/2 并且只收集 gen 0,我会得到一些幸存的对象。
所以我想说我的观点仍然成立。GC 将收集它收集的一代中的所有对象。除非你有一些特定的用例,否则你可能最好不要弄乱 WeakReferences。
推荐阅读
- azure-devops - 可以使用 Wiql 查询检索工作项下的所有树
- reactjs - 在 React.Children.map 中将函数从父级传递给子级?
- sql - 检查sql代码是否正常工作的正确方法是什么?
- c - BestFit 算法实现。仅显示第一个输出
- kubernetes - 创建 k8s pod 时如何添加用户名
- python - nidaqmx co_channels 无法写入样本并继续写入样本
- ruby-on-rails - rails accept_nested_attributes_for 无法更新
- javascript - Vue组件不更新状态更改
- mysql - MariaDB:如何使用 STR_TO_DATE 考虑本地日期格式?
- rest - 现在使用 Ansible 将 CSV 附加到服务记录