为什么我不能写超过 2GB?

Why can't I write more than 2GB?

我正在使用这段代码来测量我电脑的写入带宽。该程序需要两个参数,我们要写入的文件的名称和 MB 的数量。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>


int main(int argc, char *argv[]) {
    struct timeval tv0, tv1;
    int chunkSize = 128, res;
    char str[chunkSize];
    
    if (argc != 3)
    perror("Usage: file_name Mb.");
     
    int megabytes = atoi(argv[2]);
    int sizeWrite = megabytes*1024*1024;
    int sizeWriteAux = sizeWrite;

    FILE * fp;
    fp = fopen (argv[1], "w+");

    res = gettimeofday(&tv0, NULL);
    if (res < 0) {
         perror ("gettimeofday");
    }
    
    while (sizeWriteAux > 0) {
     fwrite(str , 1 , chunkSize , fp );
        sizeWriteAux -= chunkSize;
    }
    
    res = gettimeofday(&tv1, NULL);
    if (res < 0) {
         perror ("gettimeofday");
    }
    
    fclose(fp);
    
    double secs = (((double)tv1.tv_sec*1000000.0 + (double)tv1.tv_usec) - ((double)tv0.tv_sec*1000000.0 + (double)tv0.tv_usec))/1000000.0;
    printf("Time: %f \n", secs);
    
    double x = sizeWrite/secs;
    double y = megabytes/secs;
    printf("Bandwith: %f bytes x sec \n", x);
    printf("Bandwith: %f Mbytes x sec \n", y);

    return(0);
}

该程序在最大 2047 MB​​ 时可以正常运行,但从 2048 MB 开始它不会写入任何内容并导致无限带宽而不会返回任何错误。

我 运行 这个程序在 VirtualBox 的 Ubuntu 20 上,有 12GB RAM 和 10GB 可用磁盘内存。

有人知道为什么会这样吗?

带宽 xy 分别是 -inf 和 inf 由于不足和溢出,因为 sizeWrite 是正的,megabytes 是负的,而 secs接近0。兆字节由于 sizeWrite = megabytes*1024*1024 中的溢出而为负,因为对于 sizeof(int) == 4,值大于 2^31 - 1。secs 接近 0 因为 sizeWriteAux 是负数,因为它被初始化为 megabytes ,这反过来意味着 while 循环根本没有 运行 。第一顺序修复是:

unsigned long sizeWrite = megabytes*1024*1024;
unsigned long sizeWriteAux = sizeWrite;

如果两个参数均未指定,您的程序将崩溃。您通常缺少错误检查。每 fclose(2):

Typically, filesystems do not flush buffers when a file is closed. If you need to be sure that the data is physically stored on the underlying disk, use fsync(2).

您还需要检查 secs 以确保它足够大,从而避免 xy 溢出。当您的值为正时使用无符号类型。

您可能对此感兴趣:

file=...
size=...
block_size=128
time dd if=/dev/zero of=$file bs=$block_size count=$(($size * 1024 * 1024 / $block_size))

您可能会看到 block_size = 4096 * n 的性能提升,其中 n 至少为 1。

int megabytes = atoi(argv[2]);
int sizeWrite = megabytes*1024*1024;
int sizeWriteAux = sizeWrite;

您正在使用 int。看来,在您的系统上 sizeof(int) == 4 (bytes)。 由于 intsigned 并且一位用于符号,因此您只能使用 31 位。

2^31 = 2147483648 (2G)

如果您会使用 unsigned int,那么

2^32 = 4294967296 (4G)

一点点改变会有什么不同,对吗?

现在想象一下,您会使用 (long) long int,即 64 位。

并且您应该注意底层文件​​系统的文件大小限制。例如,Fat 的文件最大限制为 2G。