C# 在.NET中绕过2 GB的收集限制
,我想我可以通过使用以下模式创建一个BigList数据类型来绕过2GB集合大小限制(顺便说一句,如果您想尝试一下,这个限制似乎是默认强加在x86应用程序上的):C# 在.NET中绕过2 GB的收集限制,c#,.net,list,exception,collections,C#,.net,List,Exception,Collections,,我想我可以通过使用以下模式创建一个BigList数据类型来绕过2GB集合大小限制(顺便说一句,如果您想尝试一下,这个限制似乎是默认强加在x86应用程序上的): 使用Microsoft.Win32; 使用制度; 使用System.Collections.Generic; 使用System.Linq; 使用系统文本; 使用系统线程; 使用System.Threading.Tasks; 名称空间注册表 { 班级计划 { 结构注册表路径 { 公共注册视图; 公共字符串路径; 公共bool-IsKey;
使用Microsoft.Win32;
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
名称空间注册表
{
班级计划
{
结构注册表路径
{
公共注册视图;
公共字符串路径;
公共bool-IsKey;
公共注册处ValueKind ValueKind;
公共字符串ValueName;
公共客体价值;
公共值;
}
公共类大列表
{
object listLock=新对象();
列表项=新列表();
int PageSize=1000000;//将其调整为在达到.NET的2 GB大小限制之前,可以增加每个列表的最大大小。
公共ulong计数=0;
int listCount=0;
公共大名单()
{
添加(新列表());
}
公共作废新增(T项)
{
锁(列表锁)
{
if(Items[listCount].Count==PageSize)
{
添加(新列表());
listCount++;
}
项目[listCount]。添加(项目);
计数++;
}
}
}
静态void Main(字符串[]参数)
{
BigList snapshotOne=新的BigList();
步行登记并填写快照(快照一);
BigList snapshotTwo=新的BigList();
步行登记并填写快照(快照二);
}
私有静态无效漫游注册表和人口快照(大列表快照)
{
列表句柄=新列表();
foreach(Enum.GetValues中的RegistryHive配置单元(typeof(RegistryHive)))
{
foreach(Enum.GetValues(typeof(RegistryView)).Cast().ToList()中的RegistryView视图。其中(x=>x!=RegistryView.Default))
{
ManualResetEvent ManualResetEvent=新的ManualResetEvent(错误);
句柄。添加(手动重置事件);
新线程(()=>
{
WalkKey(快照、视图、注册表项、OpenBaseKey(配置单元、视图));
manualResetEvent.Set();
}).Start();
}
}
ManualResetEvent.WaitAll(handles.ToArray());
}
私有静态void WalkKey(BigList快照、RegistryView视图、RegistryKey)
{
RegistryPath path=new RegistryPath{View=View,path=key.Name,HashValue=(View.GetHashCode()^key.Name.GetHashCode()).GetHashCode()};
snapshot.Add(路径);
字符串[]valueNames=null;
尝试
{
valueNames=key.GetValueNames();
}
捕获{}
if(valueNames!=null)
{
foreach(valueNames中的字符串valueName)
{
RegistryValueKind valueKind=RegistryValueKind.Unknown;
尝试
{
valueKind=key.GetValueKind(valueName);
}
捕获{}
对象值=key.GetValue(valueName);
RegistryPath pathForValue=new RegistryPath{View=View,Path=key.Name,ValueKind=ValueKind,ValueName=ValueName,Value=Value,HashValue=(View.GetHashCode()^key.Name.GetHashCode()^ValueKind.GetHashCode()).GetHashCode()};
snapshot.Add(pathForValue);
}
}
string[]subKeyNames=null;
尝试
{
subKeyNames=key.GetSubKeyNames();
}
捕获{}
if(子关键字名称!=null)
{
foreach(subKeyName中的字符串subKeyName)
{
尝试
{
WalkKey(快照、视图、key.OpenSubKey(subKeyName));
}
捕获{}
}
}
}
}
}
但是,CLR仍然会触发
System.OutOfMemory
异常。它不会在任何地方抛出,但我看到程序执行完全停止在2GB左右的RAM上,当我在Visual Studio中冻结代码时,它表明每当我试图查看应用程序任何线程中的变量状态时,都会抛出内存不足异常。在第一次调用WalktheRegistr并填充快照(snapshotOne)时,不会发生这种情况代码>,但当第二次调用WalktheRegistr并填充快照(快照二)时代码>继续,它最终会在我的集合中总RAM使用量约为2GB的情况下停止程序执行。整个代码都已发布,因此如果您有一个强大的注册表,您可能会看到它是在x86控制台应用程序上生成的。是否有我在这里没有掌握的东西,或者这个模式不是绕过2 GB集合大小限制的有效方法,而堆栈上的另一个问题似乎达到了这个限制?我将对我的评论进行扩展。如果您正在编写一个32位应用程序,那么在处理大量数据时,您会遇到一些严重的内存限制
需要记住的最重要的一点是,32位应用程序的内存限制为绝对最大2^32字节(4 GB)。实际上,它通常是2GB,如果您有那么多内存并且应用程序具有大的地址感知能力,则可能是3MB
还有.NET强加的2GB限制,这限制了
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace RegistryHawk
{
class Program
{
struct RegistryPath
{
public RegistryView View;
public string Path;
public bool IsKey;
public RegistryValueKind ValueKind;
public string ValueName;
public object Value;
public int HashValue;
}
public class BigList<T>
{
object listLock = new object();
List<List<T>> Items = new List<List<T>>();
int PageSize = 1000000; // Tweak this to be the maximum size you can grow each individual list before reaching the 2 GB size limit of .NET.
public ulong Count = 0;
int listCount = 0;
public BigList()
{
Items.Add(new List<T>());
}
public void Add(T item)
{
lock (listLock)
{
if (Items[listCount].Count == PageSize)
{
Items.Add(new List<T>());
listCount++;
}
Items[listCount].Add(item);
Count++;
}
}
}
static void Main(string[] args)
{
BigList<RegistryPath> snapshotOne = new BigList<RegistryPath>();
WalkTheRegistryAndPopulateTheSnapshot(snapshotOne);
BigList<RegistryPath> snapshotTwo = new BigList<RegistryPath>();
WalkTheRegistryAndPopulateTheSnapshot(snapshotTwo);
}
private static void WalkTheRegistryAndPopulateTheSnapshot(BigList<RegistryPath> snapshot)
{
List<ManualResetEvent> handles = new List<ManualResetEvent>();
foreach (RegistryHive hive in Enum.GetValues(typeof(RegistryHive)))
{
foreach (RegistryView view in Enum.GetValues(typeof(RegistryView)).Cast<RegistryView>().ToList().Where(x => x != RegistryView.Default))
{
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
handles.Add(manualResetEvent);
new Thread(() =>
{
WalkKey(snapshot, view, RegistryKey.OpenBaseKey(hive, view));
manualResetEvent.Set();
}).Start();
}
}
ManualResetEvent.WaitAll(handles.ToArray());
}
private static void WalkKey(BigList<RegistryPath> snapshot, RegistryView view, RegistryKey key)
{
RegistryPath path = new RegistryPath { View = view, Path = key.Name, HashValue = (view.GetHashCode() ^ key.Name.GetHashCode()).GetHashCode() };
snapshot.Add(path);
string[] valueNames = null;
try
{
valueNames = key.GetValueNames();
}
catch { }
if (valueNames != null)
{
foreach (string valueName in valueNames)
{
RegistryValueKind valueKind = RegistryValueKind.Unknown;
try
{
valueKind = key.GetValueKind(valueName);
}
catch { }
object value = key.GetValue(valueName);
RegistryPath pathForValue = new RegistryPath { View = view, Path = key.Name, ValueKind = valueKind, ValueName = valueName, Value = value, HashValue = (view.GetHashCode() ^ key.Name.GetHashCode() ^ valueKind.GetHashCode() ^ valueName.GetHashCode()).GetHashCode() };
snapshot.Add(pathForValue);
}
}
string[] subKeyNames = null;
try
{
subKeyNames = key.GetSubKeyNames();
}
catch { }
if (subKeyNames != null)
{
foreach (string subKeyName in subKeyNames)
{
try
{
WalkKey(snapshot, view, key.OpenSubKey(subKeyName));
}
catch { }
}
}
}
}
}