c# for循环中的内存不足异常

本文关键字:内存不足 异常 for 循环 | 更新日期: 2023-09-27 18:12:22

我正在读取二进制文件。如果我读取一个文件,我的代码工作得很好。但是当我读取文件夹中的文件时,我得到错误,粘贴在下面。我将添加一些代码,我用来读取文件。我正在读取字节数组中的文件:

byte[] b = File.ReadAllBytes(args);

和在数组中存储数据(指示性代码):

len=400000000;
public ArrayList rawData1 = new ArrayList();
UInt32[] fff = Enumerable.Repeat((UInt32)4095, len/4).ToArray();    

public ReadRawFiles{
            while (true){
            rawData1.Add((double)(BitConverter.ToUInt32(b, curPos) & fff[i]));
            i++;
            }
}
b=null; //clear array

如果我只读取一个文件,它可以工作,虽然很慢(大小约为40 MB)。但是当我添加文件夹的路径并再次读取时,我得到了错误。

List<ReadRawFiles> list = new List<ReadRawFiles>();
ReadRawFiles rawFiles;
foreach (var f in sFiles)
                    {
                      rawFiles = new ReadRawFiles(f.File,true,true);
                      list.Add(rawFiles);
                       //rawFiles=null; //clear??
                    }

我不是很清楚垃圾收集器是如何工作的。如果我错过了什么,请告诉我。

提前谢谢你。

编辑:代码:http://www.codesend.com/view/4aadd067dfd26ea88396afbd3cd3fc22/http://www.codesend.com/view/f8f798224e54c28a00865ca9aff514e5/

System.OutOfMemoryException was unhandled
  Message=Exception of type 'System.OutOfMemoryException' was thrown.
  Source=System.Core
  StackTrace:
       at System.Linq.Buffer`1.ToArray()
       at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
       at program.ReadRawFiles..ctor(String args, Nullable`1 flagraw, Nullable`1 dualChannel) in E:'projects'development'vs_test'WpfApplication1'WpfApplication1'param.cs:line 83
       at SePSI.MainWindow.Add_folder(Object sender, RoutedEventArgs e) in E:'projects'development'vs_test'WpfApplication1'WpfApplication1'MainWindow.xaml.cs:line 196
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
       at System.Windows.Controls.MenuItem.InvokeClickAfterRender(Object arg)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
       at System.Windows.Threading.DispatcherOperation.InvokeImpl()
       at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Threading.DispatcherOperation.Invoke()
       at System.Windows.Threading.Dispatcher.ProcessQueue()
       at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
       at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
       at System.Windows.Application.RunDispatcher(Object ignore)
       at System.Windows.Application.RunInternal(Window window)
       at System.Windows.Application.Run(Window window)
       at System.Windows.Application.Run()
       at SePSI.App.Main() in E:'projects'development'vs_test'WpfApplication1'WpfApplication1'obj'x86'Debug'App.g.cs:line 0
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

c# for循环中的内存不足异常

这里有一些非常低效的部分;一个是将整个文件加载到内存中,另一个是将不清楚的fff数组加载到内存中。ArrayList容纳double的三分之一(这涉及到拳击每个double -在这里非常糟糕)。

我强烈建议尝试简化和数据,例如:

byte[] buffer = new byte[4];
List<double> rawData = new List<double>();
foreach(var path in paths)
{
    using(var file = File.OpenRead(path))
    {
        while(TryRead(file, buffer, 4))
        {
            const uint MASK = 4095;
            var val = BitConverter.ToUInt32(buffer, 0) & MASK;
            // note that this line looks really dodgy
            rawData.Add((double)val);
        }
    }
}

使用实用程序方法填充4字节的整个块(否则会失败):

static bool TryRead(Stream s, byte[] buffer, int bytes)
{
    int read = s.Read(buffer, 0, bytes), offset;
    if (read <= 0) return false; // no more data
    bytes -= read;
    offset = read;
    while (bytes > 0 && (read = s.Read(buffer, offset, bytes)) > 0)
    {
        bytes -= read;
        offset += read;
    }
    if (bytes != 0) throw new EndOfStreamException();
    return true; // success
}

但我必须强调:

  • uintdouble的转换看起来不太可能;这是而不是你将如何读取二进制的double
  • 将所有数据存储为double听起来同样不太可能-我想不出任何明显的场景,这将是有用的

我认为这是由于这个:

while (true)
{
    rawData1.Add((double)(BitConverter.ToUInt32(b, curPos) & fff[i]));
    i++;
}

没有终止条件,它将永远继续下去,并通过增加i和向rawData数组列表中添加数据来继续消耗资源。