10 fold size increase when reading file into struct
c++, struct
Solution
I tested your code with an input file that has `1886850` lines of text, with a size of `105M`.
With your code, the memory consumption was about 2.5G.
Then, I started modifying how data is stored.
First test:
Change `datStr` to:
struct datStr{
vector<string> colNames;
vector<string> lines;
};
This reduced the memory consumption to `206M`. That's more than 10 fold reduction in size. It's clear that the penalty for using
vector<vector<string>> data;
is rather stiff.
Second test:
Change `datStr` to:
struct datStr{
vector<string> colNames;
vector<string> lines;
vector<vector<string::size_type>> indices;
};
with `indices` keeping track of where the tokens in `lines` start. You can extract the tokens from each line by using `lines` and `indices`.
With this change, the memory consumption went to `543MB` but sill is five times smaller than the original.
Third test
Change `dataStr` to:
struct datStr{
vector<string> colNames;
vector<string> lines;
vector<vector<unsigned int>> indices;
};
With this change, the memory consumption came down to `455MB`. This should work if you don't expect your lines to be longer or equal to `UINT_MAX`.
Fourth Test
Change `dataStr` to:
struct datStr{
vector<string> colNames;
vector<string> lines;
vector<vector<unsigned short>> indices;
};
With this change, the memory consumption came down to `278MB`. This should work if you don't expect your lines to be longer or equal to `USHRT_MAX`. For this case, the overhead of `indices` is really small, only `72MB`.
Here's the modified code I used for my tests.
#include<iomanip>
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<fstream>
#include<string.h>
#include<sstream>
#include<math.h>
#include<vector>
#include<algorithm>
#include<array>
#include<ctime>
// #include<boost/algorithm/string.hpp>
using namespace std;
struct datStr{
vector<string> colNames;
vector<string> lines;
vector<vector<unsigned short>> data;
};
void split(vector<unsigned short>& rowStr, string const& line)
{
string::size_type begin = 0;
string::size_type end = line.size();
string::size_type iter = begin;
while ( iter != end)
{
++iter;
if ( line[iter] == ',' )
{
rowStr.push_back(static_cast<unsigned short>(begin));
++iter;
begin = iter;
}
}
if (begin != end )
{
rowStr.push_back(static_cast<unsigned short>(begin));
}
}
datStr readBoost(string fileName)
{
datStr ds;
ifstream inFile;
inFile.open(fileName);
string line;
getline(inFile, line);
vector<string> colNames;
stringstream ss(line);
string item;
int i = 0;
vector<int> colTypeInt;
while(getline(ss, item, ','))
{
item.erase( remove( item.begin(), item.end(), ' ' ), item.end() );
ds.colNames.push_back(item);
}
int itr = 0;
while(getline(inFile, line))
{
ds.lines.push_back(line);
vector<unsigned short> rowStr;
split(rowStr, line);
ds.data.push_back(rowStr);
}
}
int main(int argc, char** argv)
{
datStr ds = readBoost(argv[1]);
while(true)
{
}
}
Problem
I am trying to read a csv file into a struct containing a vector of vector of strings. The file contains ~2 million lines and size on disk is ~350 mb. When I read the file into struct `top` shows me that the on reading the full file, the program is now using almost 3.5GB of my memory. I have used vector reserve to try to limit vector capacity increase on push_back. ``` #include<iomanip> #include<stdio.h> #include<stdlib.h> #include<iostream> #include<fstream> #include<string.h> #include<sstream> #include<math.h> #include<vector> #include<algorithm> #include<array> #include<ctime> #include<boost/algorithm/string.hpp> using namespace std; struct datStr{ vector<string> colNames; vector<vector<string>> data; }; datStr readBoost(string fileName) { datStr ds; ifstream inFile; inFile.open(fileName); string line; getline(inFile, line); vector<string> colNames; stringstream ss(line); string item; int i = 0; vector<int> colTypeInt; while(getline(ss, item, ',')) { item.erase( remove( item.begin(), item.end(), ' ' ), item.end() ); colNames.push_back(item); vector<string> colVec; ds.data.push_back(colVec); ds.data[i].reserve(3000000); i++; } int itr = 0; while(getline(inFile, line)) { vector<string> rowStr; boost::split(rowStr, line, boost::is_any_of(",")); for(int ktr = 0; ktr < rowStr.size(); ktr++) { rowStr[ktr].erase( remove( rowStr[ktr].begin(), rowStr[ktr].end(), ' ' ), rowStr[ktr].end() ); ds.data[ktr].push_back(rowStr[ktr]); } itr++; } int main() { datStr ds = readBoost("file.csv"); while(true) { } } ``` PS: The last `while` is just so I can monitor the memory usage on completion of the program. Is this something expected when using vectors or am I missing something here? Another interesting fact. I started adding up size and capacity for each string in the read loop. Surprisingly it just adds up to 1/10 of what I am shown in top on ubuntu? Could it be that top is misreporting or my compiler is allocating too much space?