基于可用物理内存的阵列大小

本文关键字:阵列 于可用 物理内存 | 更新日期: 2023-09-27 18:27:27

我正在尝试制作一个加密算法。我可以毫无问题地读取文件并将其转换为字节,并将字节保存在byteArray中。

问题是我目前正在创建这样的数组大小:

byte[] FileArray =new byte[10000000];
FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open);
BinaryReader TheFileBinary = new BinaryReader(TheFileStream);
for (int i = 0; i < TheFileStream.Length; i++) {
    FileArray = TheFileBinary.ReadBytes(10000000);
    // I call a function here
    if (TheFileStream.Position == TheFileStream.Length)
        break;
}

然而,我不希望数组大小是固定的,因为如果我将其设置为1000000(例如),其他内存大小较小的机器可能会面临问题。我需要为每台机器找到内存大小的空闲大小,我如何根据空闲的未分配内存空间动态设置数组大小,以便在我可以将其放入byteArray的地方使用?

我注意到Arraysize越大,读取速度就越快,所以我也不想让它太小。我真的很感激你的帮助。

基于可用物理内存的阵列大小

FileStream跟踪文件中的字节数。只需使用Length属性。

FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open);
BinaryReader TheFileBinary = new BinaryReader(TheFileStream);
byte[] FileArray = TheFileBinary.ReadBytes(TheFileStream.Length);

好吧,重读这个问题,finnaly发现其中有一部分是问题,"我怎么知道空闲的未分配内存空间,这样我就可以把它放在字节数组中"。无论如何,我建议你看看这个问题以及它的最高评价。

如果你真的担心空间,那么使用一个简单的List,一次读取流的块(比如1024),并调用列表上的AddRange方法。完成后,在List上调用ToArray,现在就有了一个大小合适的字节数组。

List<byte> byteArr = new List<byte>();
byte[] buffer = new byte[1024];
int bytesRead = 0;
using(FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open))
{
    while((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
        byteArr.AddRange(buffer);
}
buffer = byteArr.ToArray();
// call your method here.

编辑:对于较大的文件,最好还是分块读取。当然,您可以随心所欲地使用缓冲区大小,但1024通常是一个不错的起点。读取整个文件最终会使内存翻倍,因为您还必须处理与流大小相同的内部读取缓冲区(位于您自己的缓冲区之上)。将读取分解为块只占用FileStream.Length + <buffer size>内存,而不是FileStream.Length * 2内存。只是需要记住的。。。

byte[] buffer = null;
using(FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open))
{
    buffer = new byte[TheFileStream.Length];
    int offset = 0;
    while((bytesRead = stream.Read(buffer, offset, 1024)) > 0)
        offset += bytesRead;
    // Or just TheFileStream.Read(buffer, 0, buffer.Length) if it's small enough.
}

您可以使用WMI检索Win32_OperatingSystem类的实例,并根据FreePhysicalMemoryTotalVisibleMemorySize属性进行内存计算:

static ulong GetAvailableMemoryKilobytes()
{
    const string memoryPropertyName = "FreePhysicalMemory";
    using (ManagementObject operatingSystem = new ManagementObject("Win32_OperatingSystem=@"))
        return (ulong) operatingSystem[memoryPropertyName];
}
static ulong GetTotalMemoryKilobytes()
{
    const string memoryPropertyName = "TotalVisibleMemorySize";
    using (ManagementObject operatingSystem = new ManagementObject("Win32_OperatingSystem=@"))
        return (ulong) operatingSystem[memoryPropertyName];
}

然后将任一方法的结果传递给这样的方法,以将读取缓冲区的大小缩放到本地机器的内存:

static int GetBufferSize(ulong memoryKilobytes)
{
    const int bufferStepSize = 256;       // 256 kilobytes of buffer...
    const int memoryStepSize = 128 * 1024;// ...for every 128 megabytes of memory...
    const int minBufferSize = 512;        // ...no less than 512 kilobytes...
    const int maxBufferSize = 10 * 1024;  // ...no more than 10 megabytes
    int bufferSize = bufferStepSize * ((int) memoryKilobytes / memoryStepSize);
    bufferSize = Math.Max(bufferSize, minBufferSize);
    bufferSize = Math.Min(bufferSize, maxBufferSize);
    return bufferSize;
}

显然,每128 MB的RAM增加256 KB的缓冲区大小似乎有点傻,但如果你真的想这样做,这些数字只是如何扩展缓冲区大小的例子。除非你同时读取很多文件,否则担心几百千字节或几兆字节的缓冲区可能会带来更大的麻烦。您最好只进行基准测试,看看哪个大小的缓冲区能提供最佳性能(它可能不需要像您想象的那么大)并使用它。

现在你可以简单地更新你的代码如下:

ulong memoryKilobytes =
    GetAvailableMemoryKilobytes();
    // ...or GetTotalMemoryKilobytes();
int bufferSize = GetBufferSize(memoryKilobytes);
using (FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open))
{
    byte[] FileArray = new byte[bufferSize];
    int readCount;
    while ((readCount = TheFileBinary.Read(FileArray, 0, bufferSize)) > 0)
    {
        // Call a method here, passing FileArray as a parameter
    }
}