C#中如何分配超过MaxInteger字节的内存我想分配超过MaxInteger字节的内存。Marshall.AllocHGlobal()需要一个整数-所以我不能使用它。还有别的办法吗?更新我将平台更改为x64并运行下面的代码。myp似乎是合适的长度:大约3.0G。而是顽固地“缓冲”到2.1G。你知道为什么吗?varfileStream=newFileStream("C:\big.BC2",FileMode.Open,FileAccess.Read,FileShare.Read,16*1024,FileOptions.SequentialScan);Int64length=fileStream.Length;控制台.WriteLine(长度);Console.WriteLine(Int64.MaxValue);IntPtrmyp=newIntPtr(长度);//IntPtrbuffer=Marshal.AllocHGlobal(myp);IntPtrbuffer=VirtualAllocEx(Process.GetCurrentProcess().Handle,IntPtr.Zero,newIntPtr(length),AllocationType.Commit|AllocationType.Reserve,MemoryProtection.ReadWrite);不安全{byte*pBytes=(byte*)myp.ToPointer();varmemoryStream=newUnmanagedMemoryStream(pBytes,(long)length,(long)length,FileAccess.ReadWrite);文件流.CopyTo(内存流);这在目前的主流硬件上是不可能的。内存缓冲区限制为2GB,即使在64位机器上也是如此。缓冲区的索引寻址仍然使用32位有符号偏移量完成。技术上可以生成可以索引更多的机器代码,使用寄存器存储偏移量,但这样做很昂贵并且会减慢所有数组索引,即使对于不大于2GB的索引也是如此。此外,您无法从32位进程可用的地址空间中获得大于650MB的缓冲区。由于虚拟内存包含位于不同地址的代码和数据,因此没有足够的连续内存页可用。像IBM和Sun这样的公司销售可以做到这一点的硬件。我参与了您提出的其他问题之一,老实说,我认为您在这里打一场必败仗。除了将所有内容读入内存之外,您还需要探索其他途径来处理这些数据。如果我理解正确的话,你有多个线程同时处理数据,这就是为什么你不想因为我假设的I/O争用而直接处理文件。您是否考虑过或者是否有可能将数据块读入内存,让线程处理该块然后读取下一个块或由线程处理?这样,在任何时候,内存中永远不会有块,但所有线程都可以访问该块。这不是最佳选择,但我将其用作起点。如果这是可行的,那么可以探索优化它的选项。更新:使用PlatformInvoke分配非托管内存并从.NET使用它的示例。由于您非常确定需要将这么多数据加载到内存中,所以我想我会编写一个小测试应用程序来验证这是否有效。为此,您需要以下内容使用/unsafe编译选项进行编译如果您分配的内存超过2GB,您还需要将目标平台切换到x64*上面的第2点有点复杂,在64位操作系统上您仍然可以定位x86平台并访问完整的4GB内存。这将要求您使用EDITBIN.EXE等工具在PE标头中设置LargeAddressAware标志。此代码使用VirtualAllocEx分配非托管内存,并使用UnmanagedMemoryStream使用.NET流隐喻访问非托管内存。请注意,此代码进行了一些非常基本的快速测试,并且仅在具有4GBRAM的目标64位环境中完成。最重要的是,我只有大约2.6GB的内存利用率。使用系统;使用System.IO;使用System.Runtime.InteropServices;使用系统诊断;使用System.ComponentModel;命名空间MemoryMappedFileTests{类程序{staticvoidMain(string[]args){IntPtrptr=IntPtr.Zero;try{//直接分配和提交内存。ptr=VirtualAllocEx(Process.GetCurrentProcess().Handle,IntPtr.Zero,newIntPtr(0xD0000000L),AllocationType.Commit|AllocationType.Reserve,MemoryProtection.ReadWrite);如果(ptr==IntPtr.Zero){thrownewWin32Exception(Marshal.GetLastWin32Error());}//查询分配的一些信息,用于测试。MEMORY_BASIC_INFORMATIONmbi=newMEMORY_BASIC_INFORMATION();IntPtr结果=VirtualQueryEx(Process.GetCurrentProcess().Handle,ptr,outmbi,newIntPtr(Marshal.SizeOf(mbi)));if(result==IntPtr.Zero){thrownewWin32Exception(Marshal.GetLastWin32Error());}//使用不安全代码获取指向非托管内存的指针。//这需要编译使用/unsafe选项。unsafe{//指向已分配内存的指针byte*pBytes=(byte*)ptr.ToPointer();//创建读/写流以访问内存。UnmanagedMemoryStreamstm=newUnmanagedMemoryStream(pBytes,mbi.RegionSize.ToInt64(),mbi.RegionSize.ToInt64(),FileAccess.ReadWrite);//创建一个StreamWriter来写入非托管内存。StreamWritersw=newStreamWriter(stm);sw.Write("一切正常!rn");sw.冲洗();//重置流位置并创建读取器以检查//数据是否正确写入。stm.Position=0;StreamReaderrd=newStreamReader(stm);Console.WriteLine(rd.ReadLine());}}catch(Exceptionex){Console.WriteLine(ex.ToString());}finally{if(ptr!=IntPtr.Zero){VirtualFreeEx(Process.GetCurrentProcess().Handle,ptr,IntPtr.Zero,FreeType.Release);}}Console.ReadKey();}[DllImport("kernel32.dll",SetLastError=true,ExactSpelling=true)]staticexternIntPtrVirtualAllocEx(IntPtrhProcess,IntPtrlpAddress,IntPtrdwSize,AllocationTypedwAllocationType,MemoryProtectionflProtect);[DllImport("kernel32.dll",SetLastError=true,ExactSpelling=true)]staticexternboolVirtualFreeEx(IntPtrhProcess,IntPtrlpAddress,IntPtrdwSize,FreeTypedwFreeType);[DllImport("kernel32.dll",SetLastError=true,ExactSpelling=true)]staticexternIntPtrVirtualQueryEx(IntPtrhProcess,IntPtrlpAddress,outMEMORY_BASIC_INFORMATIONlpBuffer,IntPtrdwLength);[StructLayout(LayoutKind.Sequential)]publicstructMEMORY_BASIC_INFORMATION{publicIntPtrBaseAddress;公共IntPtrAllocationBase;公共诠释分配保护;公共IntPtr区域大小;公共诠释状态;公共诠释保护;公共int类型;}[Flags]publicenumAllocationType{Commit=0x1000,Reserve=0x2000,Decommit=0x4000,Release=0x8000,Reset=0x80000,Physical=0x400000,TopDown=0x100000,WriteWatch=0x200000,LargePages=0x20000000}[ags]publicenumMemoryProtection{Execute=0x10,ExecuteRead=0x20,ExecuteReadWrite=0x40,ExecuteWriteCopy=0x80,NoAccess=0x01,ReadOnly=0x02,ReadWrite=0x04,WriteCopy=0x08,GuardModifierflag=0x100,NoCacheModifierflag=0x200,WriteCombineModifierflag=0x400}[Flags]publicenumFreeType{Decommit=0x4000,Release=0x8000}}}没有pinvoke调用的托管代码是不可能的,并且有充分的理由分配这么多内存通常是一个需要重新访问的糟糕解决方案的标志。你能告诉我们为什么你认为你需要这么多内存吗?使用Marshal.AllocHGlobal(IntPtr)。此重载将IntPtr的值视为要分配的内存量,并且IntPtr可以保存64位值。来自评论:如何创建可以独立读取相同内存流的第二个二进制读取器?varfileStream=newFileStream("C:\big.BC2",FileMode.Open,FileAccess.Read,FileShare.Read,16*1024,FileOptions.SequentialScan);Int64length=fileStream.Length;IntPtrbuffer=Marshal.AllocHGlobal(长度);不安全{byte*pBytes=(byte*)myp.ToPointer();varmemoryStream=newUnmanagedMemoryStream(pBytes,(long)length,(long)length,FileAccess.ReadWrite);varbinaryReader=newBinaryReader(memoryStream);文件流.CopyTo(内存流);memoryStream.Seek(0,SeekOrigin.Begin);//在相同的内存缓冲区上创建第二个UnmanagedMemoryStreamvarmemoryStream2=newUnmanagedMemoryStream(pBytes,(long)length,File(long)length,File(long)length,Read);varbinaryReader2=newBinaryReader(memoryStream);如果你不能让它按照你想要的方式工作,创建一个类来提供你想要的行为类型。所以,要使用大数据组:usingSystem;使用System.Collections.Generic;使用系统文本;使用System.IO;namespaceBigBuffer{classStorage{publicStorage(stringfilename){m_buffers=newSortedDictionary();m_file=newFileStream(文件名,FileMode.Open,FileAccess.Read,FileShare.Read);}publicbyte[]GetBuffer(longaddress){intkey=GetPageIndex(address);字节[]缓冲区;if(!m_buffers.TryGetValue(key,outbuffer)){System.Diagnostics.Trace.WriteLine("Allocatinganewarrayat"+key);缓冲区=新字节[10];}publicintGetPageIndex(longaddress){return(int)(address>>24);}publicintGetPageOffset(longaddress){return(int)(address&((1m_buffers;}classBigStream:Stream{publicBigStream(Storagesource){m_source=source;m_position=0;}publicoverrideboolCanRead{get{返回true;}}publicoverrideboolCanSeek{get{returntrue;}}publicoverrideboolCanTimeout{get{returnfalse;}}publicoverrideboolCanWrite{get{returnfalse;}}publicoverridelongLength{get{returnm_source.Length;}}publicoverridelongPosition{get{returnm_position;}设置{m_position=值;}}publicoverridevoidFlush(){}publicoverridelongSeek(longoffset,SeekOriginorigin){switch(origin){caseSeekOrigin.Begin:m_position=offset;休息;caseSeekOrigin.Current:m_position+=offset;休息;caseSeekOrigin.End:m_position=Length+offset;休息;}返回m_位置;}publicoverridevoidSetLength(longvalue){}publicoverrideintRead(byte[]buffer,intoffset,intcount){intbytes_read=(int)(m_position+count>Length?Length-m_position:count);m_source.FillBuffer(buffer,offset,bytes_read,m_position);m_position+=bytes_read;返回bytes_read;}publicoverridevoidWrite(byte[]buffer,intoffset,intcount){}Storagem_source;长头寸;}classIntBigArray{publicIntBigArray(存储存储){m_storage=存储;m_current_page=-1;}publicintthis[longindex]{get{intvalue=0;index");BigStreamstream=newBigStream(storage);StreamReaderreader=newStreamReader(stream);stringline=reader.ReadLine();IntBigArrayarray=newIntBigArray(storage);intvalue=array[0];BinaryReaderbinary=newBinaryReader(stream);binary.BaseStream.Seek(0,SeekOrigin.Begin);intanother_value=binary.ReadInt32();}}}我将问题分为三类:以上可以显着改进,butitshouldgiveyouanideaof??howtosolvetheproblem以上是C#学习教程:HowtoAssigninC#如果想了解更多C#学习教程,请多多关注记忆的全部内容分享超过MaxInteger字节,本文整理自网络,不代表立场,如涉及侵权,请点击右边联系管理员删除,如需转载请注明出处:
