• 请不要在回答技术问题时复制粘贴 AI 生成的内容
SmartTom
0.12D
V2EX  ›  程序员

关于 C++读取大小为 2.51 GB (2,701,131,776 字节)到 char* yuanshuju 数组中去

  •  
  •   SmartTom · Mar 21, 2024 · 4538 views
    This topic created in 959 days ago, the information mentioned may be changed or developed.
    如题,现在想实现将这个大文件(大小超过 int 最大范围)的文件放入到 char* yuanshuju = new char[2,701,131,776]中
    现在就卡在第一步定义 yuanshuju 这一步,qt 一直提示"terminate called after throwing an instance of 'std::bad_alloc'
    what(): std::bad_alloc",本人没太做过 c++,这个提示是代表不能定义那么大的数组吗?还有别的可行方案吗。
    系统:win11 64 位
    QT: 5.12.12
    Supplement 1  ·  Mar 21, 2024

    发现问题了。 问题代码:

    qint64 dataSize = 2701131776;
    char* yuanshuju = new char[dataSize];
    

    可行代码:

    char* yuanshuju = new char[2701131776];
    

    c++,牛 我反正是没搞懂

    45 replies  •  2024-03-21 21:40:25 +08:00
    yougg
    yougg
    Mar 21, 2024❤️3
    1
    先把变量名改为 metadata 吧, 看到这里就难受无法继续阅读了......
    proxytoworld
    proxytoworld
    Mar 21, 2024
    2
    同意一楼的
    iOCZS
    iOCZS
    Mar 21, 2024❤️2
    3
    是 rawdata ,不是 metadata
    @yougg
    deplives
    deplives
    Mar 21, 2024
    4
    这个 yuanshuju 血压升高
    Mithril
    Mithril
    Mar 21, 2024❤️4
    5
    用 memory mapping ,不要手动去读它。
    silentx
    silentx
    Mar 21, 2024
    6
    是啥东西要一次性读到内存里处理?不考虑分段读吗?不是每个人的机器都是 32G 内存起步的啊。。。
    Yasuke
    Yasuke
    Mar 21, 2024
    7
    不知道一次性读 2.51GB 数据的应用场景是什么
    SmartTom
    SmartTom
    OP
    Mar 21, 2024
    8
    @deplives 哈哈 我也是接手别人的项目,这不是我的风格。
    geelaw
    geelaw
    Mar 21, 2024❤️2
    9
    new char[2,701,131,776] 会分配长度是 776 个元素的 char 数组,不是你期待的 2.51 GB 。

    int main() { new char[2701131776] { }; }

    这个程序在我的电脑上编译为 64 位的话可以正常运行,并且确实占用了 2.51 GB 内存,如果用 32 位编译器则编译失败,因为分配的数组规模超过了 size_t 。

    抛出 std::bad_alloc 的意思就是分配失败,或许你的页面文件和实体内存不够大。

    如果数据来自于文件,可以用内存映射文件,Windows 的文档是 https://learn.microsoft.com/en-us/windows/win32/memory/file-mapping
    POSIX 的文档是 https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html
    SmartTom
    SmartTom
    OP
    Mar 21, 2024
    10
    @maokg 光谱数据处理,体谅挺大的
    Crawping
    Crawping
    Mar 21, 2024
    11
    理论 64 位程序的寻址空间是可以到 2'64 次字节
    ```C++
    //你是真的这么写的 还是手写拷贝的? 中间为啥会有 ',' 逗号
    char* yuanshuju = new char[2,701,131,776]
    ```
    学其他语言问 GPT 比发帖要来得快
    geelaw
    geelaw
    Mar 21, 2024❤️1
    12
    @geelaw #9 没有超过 size_t (((φ(◎ロ◎;)φ))) 是 MSVC 只支持至多 2147483647 个元素。
    SmartTom
    SmartTom
    OP
    Mar 21, 2024
    13
    @Crawping 这个我的问题,我是手动在编辑标题的时候赋值计算器里面的值,实际是去掉','的
    yougg
    yougg
    Mar 21, 2024
    14
    @iOCZS #3 "元数据"不是"原始数据"
    tool2d
    tool2d
    Mar 21, 2024
    15
    我用 malloc ,别说是 malloc(2701131776)可以, 就算 malloc(4701131776)也行。

    应该只是你内存不够的原因。”不够“不是说总剩余内存不够,而是无法分配一块巨大内存。
    momo1999
    momo1999
    Mar 21, 2024
    16
    改成 64 位轻轻松松。
    greycell
    greycell
    Mar 21, 2024
    17
    笑死,元数据 2 个 g ,还在嘴硬。
    MoYi123
    MoYi123
    Mar 21, 2024❤️1
    18
    建议发一下编译器的版本

    或者试试看这样写
    auto alloc = vector<int64_t>(2701131776 / 8 + 1);
    char* yuanshuju = reinterpret_cast<char*>(alloc.data());
    clue
    clue
    Mar 21, 2024
    19
    能流式处理不? 为什么一定要全读到内存里?
    roykingH
    roykingH
    Mar 21, 2024
    20
    从原数据着手吧 一次申请几个 G 的内存就算这次运行不出问题 下次也会崩
    修改方法:1,分段读取 分段解析
    2,优化算法 保存分段前后缓存数据和状态
    yolee599
    yolee599
    Mar 21, 2024
    22
    这么大一个数组,我看着都头疼,考虑分多次处理吧,每次大概分配 4096 字节
    shawnsh
    shawnsh
    Mar 21, 2024 via Android
    23
    大力出奇迹啊,先设计设计
    SmartTom
    SmartTom
    OP
    Mar 21, 2024
    24
    发现问题了。
    问题代码:
    qint64 dataSize = 2701131776;
    char* yuanshuju = new char[dataSize];
    可行代码:
    char* yuanshuju = new char[2701131776];

    c++,牛 我反正是没搞懂
    SmartTom
    SmartTom
    OP
    Mar 21, 2024
    25
    @yolee599 是头疼,等一次采集任务结束,还要处理 50GB 的数据,哎~
    iold
    iold
    Mar 21, 2024❤️2
    26
    @SmartTom #24 试试使用文档中提供的宏呢?
    zhangshaohan
    zhangshaohan
    Mar 21, 2024
    27
    我还以为是 yushengjun (余胜军)
    amorphobia
    amorphobia
    Mar 21, 2024
    28
    @SmartTom

    C++ 标准不支持“柔性数组/变长数组”,数组大小是变量的情况,应该用 vector

    一定要使用变量作数组长度的话,换 C 语言 (C99) 吧
    vsomeone
    vsomeone
    Mar 21, 2024❤️1
    29
    根据你给的附言,推测可能是你 qtglobal 头文件引入的有问题,导致 qint64 被认为是 int32_t 。因为 2701131776 > INT_MAX(1 << 32 - 1),这个值在 assign 给 int32_t dataSize 之后被认为是一个负数,导致 bad_alloc 。
    vsomeone
    vsomeone
    Mar 21, 2024
    30
    @amorphobia 他这个不是变长数组呀,用了 new 分配在堆上的,变长数组指的是分配在栈上的
    nagisaushio
    nagisaushio
    Mar 21, 2024 via Android
    31
    这么大文件为什么不 mmap?
    MrKrabs
    MrKrabs
    Mar 21, 2024
    32
    2.51G 就大了?你们用的都是黄金内存吗
    amorphobia
    amorphobia
    Mar 21, 2024 via iPhone
    33
    @vsomeone 是我想错了
    march1993
    march1993
    Mar 21, 2024
    34
    一个动态申请的,一个是放在静态区的?
    JustdoitSoso
    JustdoitSoso
    Mar 21, 2024 via Android❤️1
    35
    @vsomeone 感觉你说的是最有可能得情况,人家来请教问题,一群没分析没讨论的在说变量命名。
    yuruizhe
    yuruizhe
    Mar 21, 2024
    36
    试试用
    constexpr qint64 dataSize = 2701131776;
    行不行?
    NEO17
    NEO17
    Mar 21, 2024
    37
    看了这段代码,不建议再写 C++ :)
    litguy
    litguy
    Mar 21, 2024
    38
    这个不是应该 mmap 的方式访问么 ?
    araraloren
    araraloren
    Mar 21, 2024
    39
    Why you need load whole data to memory?
    ltyj2003
    ltyj2003
    Mar 21, 2024 via Android
    40
    动态长度用 vector
    或者定义一个 char* ,然后 malloc 分配内存空间。
    cnbatch
    cnbatch
    Mar 21, 2024
    41
    @amorphobia 这么大的 VLA ,存在爆栈的可能性吧(视乎编译器做法而定)
    amorphobia
    amorphobia
    Mar 21, 2024
    42
    @cnbatch

    是我想错了,这里不是 VLA

    如果真有这么大的 VLA ,我也高度怀疑会爆
    cnbatch
    cnbatch
    Mar 21, 2024❤️2
    43
    等等,为什么要用 new 直接创建呢?最后还得手动 delete 。
    不如用 std::vector 或者 std::make_unique<char[]>(数据长度)
    这两个好多了

    std::vector 已经有人发了,那么 make_unique 的用法是:

    size_t data_size{2701131776};
    std::unique_ptr<char[]> raw_data_ptr = std::make_unique<char[]>(data_size);
    char* raw_data = raw_data_ptr.get();

    在我的 Windows 11 + VS2022 测了下,很成功,没任何报错。

    另外呢,直接用 malloc 、new 创建的空间,按照 C 语言留下来的“惯例”,是需要手动初始化的。
    通常会用 memset 初始化为零,用 std::fill 也可以。

    如果改用 std::vector 或者 std::make_unique ,就可以跳过这一步,它们都会自动初始化。
    yougotme
    yougotme
    Mar 21, 2024 via iPhone
    44
    @SmartTom 立即数后面加上 LL ,明确指定长度。否则编译器可能会误判你是 int32 转 int64 ,可能变负数、可能溢出。
    yougotme
    yougotme
    Mar 21, 2024 via iPhone
    45
    vs2022 肯定会抛一个警告出来的,也许你忽略了或者编译器不够新
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4846 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 99ms · UTC 07:56 · PVG 15:56 · LAX 23:56 · JFK 02:56
    ♥ Do have faith in what you're doing.