List<List<float>> 达到内存限制

Posted

技术标签:

【中文标题】List<List<float>> 达到内存限制【英文标题】:List<List<float>> hitting memory limits 【发布时间】:2020-09-04 14:12:59 【问题描述】:

当我打开大型音频文件时,出现内存不足错误。

我知道这种方法不常见,所以我想我必须请教真正的博芬。

我发生了以下事情:

public static List<List<float>> int_filenamewavedataRight = new List<List<float>>();

从那里我打开一个音频文件并将音频电平值加载到这个数组中,这样我就可以通过 naudio 库正确查看它们。

我像这样为一个新文件清除数组:

int_filenamewavedataRight.Clear();

int_filenamewavedataRight.Add(new List<float>());

然后,我将所有值加载到内存中以快速显示波形:

waveStream.Position = 0;
int bytesRead; 
byte[] waveData = new byte[bytesPerSample];
waveStream.Position = 0; // startPosition + (e.ClipRectangle.Left * bytesPerSample * samplesPerPixel);

int samples = (int)(waveStream.Length / bytesPerSample);

wavepeakloaded = 0;
int OldPrecentVal = 0;

for (int x = 0; x < samples; x++)

     
    short high = 0;

    bytesRead = waveStream.Read(waveData, 0, bytesPerSample);
    if (bytesRead == 0)
        break;


    for (int n = 0; n < bytesRead; n += 2)
    
        short sample = BitConverter.ToInt16(waveData, n); 
        if (sample > high) high = sample;
    

    float highPercent2 = (float)Math.Round(((((float)high) - short.MinValue) / ushort.MaxValue), 2);              

    // ERRORING HERE
    // ERRORING HERE

    int_filenamewavedataRight[filename_value].Add((float)Math.Round(highPercent2, 2)); 

    // ERRORING HERE
    // ERRORING HERE


一首 5 分钟长的典型歌曲的小音频文件很好,但 25 分钟或更长的较长文件会在发生 67108864 的计数时创建一个异常,然后我得到一个“类型为‘System.Exception’的异常。抛出 OutOfMemoryException'。”

x = "Exception of type 'System.OutOfMemoryException' was thrown." 

ex.StackTrace "   at System.Collections.Generic.List`1.set_Capacity(Int32 value)\r\n   at System.Collections.Generic.List`1.EnsureCapacity(Int32 min)\r\n   at System.Collections.Generic.List`1.Add(T item)\r\n   at APP.WaveViewer.LoadWaveToMemory(Int32 filename_value) in  WaveViewer.cs:line 1391"

我正在使用列表的列表,这样我就可以像一个简单的数组一样处理音频文件,但由于我不知道数组的初始大小,我可以在初始时指定一个大小。

我还像这样预加载波形数据,这样我就可以同时播放、缩放和平移音频文件。

这很容易解决吗,或者我应该找到其他方法来解决这个问题,例如将这些峰值音量值写入临时文件,而不是将它们保存在内存中,还是有更好的方法?

我在网上的各个地方都查到了这个,比如here,但是,这样做似乎很少见。

谢谢。

【问题讨论】:

如果你有一个很大的数组,使用那个标志是合理的。从概念的角度来看,Int32 是一个相当随意的限制。 我认为这个数据结构: public static List> int_filenamewavedataRight = new List>();是有问题的。考虑一下:Span 和 Memory。我还会考虑在适当的时候使用垃圾收集 API 来释放资源。您还可以使用多线程来管理任务。在内存达到最大值之前,让线程等待,然后继续。使用诊断类来实现此目的并进行一般调试。 您确定您没有在 32 位模式下运行您的进程吗? @JonasH 即使在 64 位版本中,单个对象仍有一个默认的 2GB 限制,正如 OP 链接的问题中所指出的那样。 @itsme86,我知道,但 67108864 浮点数应该离 2Gb 限制相当远。如果他在运行32位问题会更快出现,一些版本的VS默认为32位,应该很容易检查。 【参考方案1】:

简单的答案是它在 32 位 (x86) 中运行,没有足够的分配来容纳 50,000,000+ 个样本。

相反,将程序更改为 x64 已解决了该特定问题。

这就是我喜欢 SO 的原因,您可以从这么多人那里汇集资源并在提问时学习。

【讨论】:

您真的需要将所有这些样本保存在内存中吗?几十年来,音频处理软件能够处理比物理内存更大的原始波形数据,因为它能够智能地了解内存中保存的内容。 是的,我完全同意,但希望未来不会太远。我刚刚找到了一个库,它可以以惊人的速度绘制事物,使我最初的努力变得多余。我现在只需要重写一些东西并进一步优化它并尝试我以前没有做过或没有想过的不同方法。

以上是关于List<List<float>> 达到内存限制的主要内容,如果未能解决你的问题,请参考以下文章

Android 踩坑 LitePal无法自动加入类似List<List>等数据类型

Java 如何打印出List中得值

java如何从List中取值

选项卡切换

vue 瀑布流实现

java怎么创建一个float类型的ArrayList,然后怎么把这个ArrayList转换成float数组。谢谢