当前位置: 首页 > 知识库问答 >
问题:

C大文件上疯狂的内存消耗

邓仲卿
2023-03-14

我正在将一个10GB的文件加载到内存中,我发现即使去掉任何额外的开销,只将数据存储在一个阵列中,它仍然需要占用53 GB的ram。这对我来说似乎太疯狂了,因为我正在将一些文本数据转换为long,而long占用更少的空间,将其余的转换为char*,char*应该占用与文本文件相同的空间。我试图加载的文件中有大约1.5亿行数据。当我按照下面的方式加载时,有什么原因会占用这么多内存吗?

这里有三个文件,一个fileLoader类及其头文件和一个简单运行它们的main。回答一些问题:操作系统是UBUNTU 12.04 64bit这是在一个具有64GB RAM和SSD hd的machien上,我为RAM提供了64GB的交换空间由于对速度的需求,我正在一次加载所有数据。这对应用程序至关重要。所有排序、索引和大量数据密集型工作都在GPU上运行。另一个原因是一次加载所有数据使我编写代码变得更加简单。我不必担心索引文件,例如映射到另一个文件中的位置。

下面是头文件:

#ifndef FILELOADER_H_
#define FILELOADER_H_
#include <iostream>
#include <fstream>

#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <string>

class fileLoader {
public:
    fileLoader();
    virtual ~fileLoader();
    void loadFile();
private:
    long long ** longs;
    char *** chars;
    long count;
    long countLines(std::string inFile);
};


#endif /* FILELOADER_H_ */

这是CPP文件

#include "fileLoader.h"



fileLoader::fileLoader() {
    // TODO Auto-generated constructor stub
    this->longs = NULL;
    this->chars = NULL;
}

char ** split(char * line,const char * delim,int size){
    char ** val = new char * [size];


    int i = 0;
    bool parse = true;
    char * curVal = strsep(&line,delim);
    while(parse){


        if(curVal != NULL){
            val[i] = curVal;
            i++;
            curVal = strsep(&line,delim);
        }else{
            parse = false;
        }

    }

    return val;
}

void fileLoader::loadFile(){
    const char * fileName = "/blazing/final/tasteslikevictory";

    std::string fileString(fileName);
    //-1 since theres a header row and we are skipinig it
    this->count = countLines(fileString) -1;

    this->longs = new long long*[this->count];
    this->chars = new char **[this->count];
    std::ifstream inFile;

    inFile.open(fileName);
    if(inFile.is_open()){
        std::string line;
        int i =0;
        getline(inFile,line);
        while(getline(inFile,line)){
            this->longs[i] = new long long[6];
            this->chars[i] = new char *[7];
            char * copy = strdup(line.c_str());
            char ** splitValues = split(copy,"|",13);

            this->longs[i][0] = atoll(splitValues[4]);
            this->longs[i][1] = atoll(splitValues[5]);
            this->longs[i][2] = atoll(splitValues[6]);
            this->longs[i][3] = atoll(splitValues[7]);
            this->longs[i][4] = atoll(splitValues[11]);
            this->longs[i][5] = atoll(splitValues[12]);

            this->chars[i][0] = strdup(splitValues[0]);
            this->chars[i][1] = strdup(splitValues[1]);
            this->chars[i][2] = strdup(splitValues[2]);
            this->chars[i][3] = strdup(splitValues[3]);
            this->chars[i][4] = strdup(splitValues[8]);
            this->chars[i][5] = strdup(splitValues[9]);
            this->chars[i][6] = strdup(splitValues[10]);
            i++;
            delete[] splitValues;
            free(copy);
        }
    }
}

fileLoader::~fileLoader() {
    // TODO Auto-generated destructor stub
    if(this->longs != NULL){
        delete[] this->longs;
    }

    if(this->chars != NULL){
        for(int i =0; i <this->count;i++ ){
            free(this->chars[i]);
        }
        delete[] this->chars;
    }

}

long fileLoader::countLines(std::string inFile){
    int BUFFER_SIZE = 16*1024;
    int fd = open(inFile.c_str(), O_RDONLY);
    if(fd == -1)
    return 0;

    /* Advise the kernel of our access pattern.  */
    posix_fadvise(fd, 0, 0, 1);  // FDADVICE_SEQUENTIAL

    char buf[BUFFER_SIZE + 1];
    long lines = 0;

    while(size_t bytes_read = read(fd, buf, BUFFER_SIZE))
    {
    if(bytes_read == (size_t)-1)
        return 0;
    if (!bytes_read)
        break;

    for(char *p = buf; (p = (char*) memchr(p, '\n', (buf + bytes_read) - p)); ++p)
        ++lines;
    }

    return lines;

}

这是我的主要功能文件:

#include "fileLoader.h"

int main()
{

fileLoader loader;
loader.loadFile();
return 0;
}

这是我正在加载的数据示例:

13|0|1|1997|113|1|4|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
14|0|1|1997|113|1|5|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
15|0|1|1997|113|1|6|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
16|0|1|1997|113|1|7|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
17|0|1|1997|113|1|8|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
18|0|1|1997|113|1|9|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
19|0|1|1997|113|1|10|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
20|0|1|1997|113|1|11|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
21|0|1|1997|113|1|12|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
9|0|1|1997|113|1|13|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
27|0|1|1992|125|1|1|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
28|0|1|1992|125|1|2|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
29|0|1|1992|125|1|3|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
30|0|1|1992|125|1|4|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
31|0|1|1992|125|1|5|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
32|0|1|1992|125|1|6|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
33|0|1|1992|125|1|7|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
34|0|1|1992|125|1|8|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
35|0|1|1992|125|1|9|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
36|0|1|1992|125|1|10|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
37|0|1|1992|125|1|11|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
38|0|1|1992|125|1|12|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
39|0|1|1992|125|1|13|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
40|0|1|1992|125|1|14|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
41|0|1|1992|125|1|15|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
10|0|1|1996|126|1|1||||||

共有2个答案

曹泉
2023-03-14

您创建的每个对象和字符串都有单独的内存管理开销。因此,您从第2列加载字符串“0”,具体取决于您的内存管理器,它可能需要两到四个完整的单词(可能更多)。将其称为16到32字节的存储空间来保存一个字节的字符串。然后从第3列加载“1”。依此类推。

陈泰宁
2023-03-14

您为每行分配了九块内存,因此您总共分配了13.5亿块内存。这些分配有一定的开销,通常至少是指针大小的两倍,甚至可能更大。在64位机器上,这已经是16个字节,因此您将获得21.6GB的开销。

此外,还存在堆碎片和对齐的开销:即使只在其中存储字符串,分配器也必须对齐内存分配,以便在其中存储尽可能大的值,而不会触发错位。对齐可能取决于CPU的向量单元,这可能需要非常重要的对齐,16字节对齐并不少见。

使用16字节分配开销和16字节对齐进行计算,我们在没有原始数据的情况下获得43.2 GB的分配。使用原始数据,此计算已经非常接近您的测量。

 类似资料:
  • 本书是一部真实再现程序员成长历程的原创小说,以作者的学习、工作、生活为原型,分为大学、工作、创业三部分,环环相扣,精彩迭出,其中作为主线的实际项目案例都基于作者深厚的技术积淀。本书生动描写了软件行业中的形形色色的人和事,形象而深刻、生动而亲切,充满了智慧的职场警句,能让不同职业的读者都受益匪浅。

  • 在尝试将相同的战争文件重新部署到野蝇中时,我总是遇到错误。有谁知道下面的错误是什么意思以及如何解决它? 错误如下:无法上载部署:{“WFLYCTL0080:失败的服务” =

  • 我正在尝试将spree store安装到我的应用程序中,当我在终端中输入时,我收到以下错误: 来源https://rubygems.org 宝石“轨道”、“4.2.5.1” 宝石'pg','~ gem'sass rails','~ 宝石“丑陋的” 宝石咖啡轨道 gem'jquery rails' gem“涡轮链接” 宝石jBuilder 创业板“sdoc”~ 小组:开发,:测试 调试器控制台gem

  • 然后,绝影的眼中流露出一片憧憬,他缓缓地说:“知道吗?我的第一份工作,也就是在周总的公司。那天面试完后周总送我回去,他问我:‘你的理想是什么?’我告诉他:‘我希望以后有一天能有一家自己的真正的软件公司。’当周总听到那句话的时候,我发现他的脸色变得很难看。是啊,他不是正经营着一家软件公司么?或许每个老板都是这样想的,希望他的员工能一心一意地呆在公司,希望他们能把他的公司当成他们自己的,希望他们能全心

  • 我必须编写一个二进制搜索树的实现,它可以处理库的库存。它读取一个包含所有书籍的文本文件,并将这些书籍按字母顺序添加到树中。我已经与Insertar()函数代码斗争了几天,但我无法使它正常工作,它基本上接收到一个指针,指向与书相关的所有数据的树根。如果根为NULL,则它将函数中输入的所有值初始化一个节点,并将内存方向指定为NULL节点。问题是,它在本地做,最终它没有分配它。谁能帮我纠正那个具体的功能

  • 1.自我介绍 2.TCP和UDP的区别 3.为什么TCP是可靠传输 4.32位系统下int,float,long 占多少字节? 5.mysql增删查改都是那几个关键字 6.mysql改变表结构关键字 7.类和结构体的区别 8.new和malloc的区别 9.linux下的命令 10.查看磁盘linux什么命令?查看进程ID什么命令?gdb打断点,查看堆栈情况什么命令? 11.memcpy和stir