V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
SmartTom
V2EX  ›  程序员

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

  •  
  •   SmartTom · 2024-03-21 09:58:00 +08:00 · 3179 次点击
    这是一个创建于 367 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如题,现在想实现将这个大文件(大小超过 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
    第 1 条附言  ·  2024-03-21 10:53:35 +08:00

    发现问题了。 问题代码:

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

    可行代码:

    char* yuanshuju = new char[2701131776];
    

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

    45 条回复    2024-03-21 21:40:25 +08:00
    yougg
        1
    yougg  
       2024-03-21 10:05:14 +08:00   ❤️ 3
    先把变量名改为 metadata 吧, 看到这里就难受无法继续阅读了......
    proxytoworld
        2
    proxytoworld  
       2024-03-21 10:07:34 +08:00
    同意一楼的
    iOCZS
        3
    iOCZS  
       2024-03-21 10:12:28 +08:00   ❤️ 2
    是 rawdata ,不是 metadata
    @yougg
    deplives
        4
    deplives  
       2024-03-21 10:13:17 +08:00
    这个 yuanshuju 血压升高
    Mithril
        5
    Mithril  
       2024-03-21 10:14:33 +08:00   ❤️ 4
    用 memory mapping ,不要手动去读它。
    silentx
        6
    silentx  
       2024-03-21 10:15:50 +08:00
    是啥东西要一次性读到内存里处理?不考虑分段读吗?不是每个人的机器都是 32G 内存起步的啊。。。
    maokg
        7
    maokg  
       2024-03-21 10:16:45 +08:00
    不知道一次性读 2.51GB 数据的应用场景是什么
    SmartTom
        8
    SmartTom  
    OP
       2024-03-21 10:16:59 +08:00
    @deplives 哈哈 我也是接手别人的项目,这不是我的风格。
    geelaw
        9
    geelaw  
       2024-03-21 10:17:06 +08:00   ❤️ 2
    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
        10
    SmartTom  
    OP
       2024-03-21 10:17:29 +08:00
    @maokg 光谱数据处理,体谅挺大的
    Crawping
        11
    Crawping  
       2024-03-21 10:19:25 +08:00
    理论 64 位程序的寻址空间是可以到 2'64 次字节
    ```C++
    //你是真的这么写的 还是手写拷贝的? 中间为啥会有 ',' 逗号
    char* yuanshuju = new char[2,701,131,776]
    ```
    学其他语言问 GPT 比发帖要来得快
    geelaw
        12
    geelaw  
       2024-03-21 10:19:53 +08:00   ❤️ 1
    @geelaw #9 没有超过 size_t (((φ(◎ロ◎;)φ))) 是 MSVC 只支持至多 2147483647 个元素。
    SmartTom
        13
    SmartTom  
    OP
       2024-03-21 10:20:14 +08:00
    @Crawping 这个我的问题,我是手动在编辑标题的时候赋值计算器里面的值,实际是去掉','的
    yougg
        14
    yougg  
       2024-03-21 10:23:18 +08:00
    @iOCZS #3 "元数据"不是"原始数据"
    tool2d
        15
    tool2d  
       2024-03-21 10:28:55 +08:00
    我用 malloc ,别说是 malloc(2701131776)可以, 就算 malloc(4701131776)也行。

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

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

    c++,牛 我反正是没搞懂
    SmartTom
        25
    SmartTom  
    OP
       2024-03-21 10:54:56 +08:00
    @yolee599 是头疼,等一次采集任务结束,还要处理 50GB 的数据,哎~
    iold
        26
    iold  
       2024-03-21 10:58:34 +08:00   ❤️ 2
    @SmartTom #24 试试使用文档中提供的宏呢?
    Geekerstar
        27
    Geekerstar  
       2024-03-21 11:16:39 +08:00
    我还以为是 yushengjun (余胜军)
    amorphobia
        28
    amorphobia  
       2024-03-21 12:08:42 +08:00
    @SmartTom

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

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

    是我想错了,这里不是 VLA

    如果真有这么大的 VLA ,我也高度怀疑会爆
    cnbatch
        43
    cnbatch  
       2024-03-21 16:19:43 +08:00   ❤️ 2
    等等,为什么要用 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
        44
    yougotme  
       2024-03-21 21:39:04 +08:00 via iPhone
    @SmartTom 立即数后面加上 LL ,明确指定长度。否则编译器可能会误判你是 int32 转 int64 ,可能变负数、可能溢出。
    yougotme
        45
    yougotme  
       2024-03-21 21:40:25 +08:00 via iPhone
    vs2022 肯定会抛一个警告出来的,也许你忽略了或者编译器不够新
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2479 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 05:43 · PVG 13:43 · LAX 22:43 · JFK 01:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.