кажется, что мое освобождение не работает должным образом. Мне нужно скопировать содержимое std::vector ‹ uint64_t > в char**, потому что используемая C-библиотека хочет этого. Для этого я написал следующий код.
Проблема. Является ли free(storage[key])
неправильным выбором, я забыл какое-то дополнительное освобождение? Потому что после этой свободной команды объем занятой памяти остается прежним, согласно «системному монитору» Ubuntu. Даже после повторного входа в основную функцию занятая память программы по-прежнему составляет около 30 МБ, что должно быть слишком много.
Я уже использовал для этого valgrind, который, кажется, не сообщает об утечке памяти.
Забавная вещь: если я несколько раз вызываю problematic_function()
, объем занятой памяти в системном мониторе остается на уровне 30 МБ и не удваивается. Это только ошибка "системного монитора"?
bool problematic_function(std::vector<uint64_t>& hashTableKeys){
// get number of keys
double numberOfKeys = hashTableKeys.size();
// copy keys into char** 'storage', because C-lib wants it like this.
char** storage = (char**)calloc( numberOfKeys, sizeof(char*));
if (storage!=nullptr){ // if calloc() succeeded
for(int key = 0; key < numberOfKeys; key++){
std::string keyString = std::to_string(hashTableKeys[key]);
storage[key] = (char *)calloc( (keyString.length()+1), sizeof(char));
if (storage[key]!=nullptr){ // if calloc() succeeded
std::strcpy(storage[key], keyString.c_str());
}
else{
return false;
}
}
}
else{
return false;
}
// pass the char** to the c-lib-function
// ...
// de-allocate the memory-blocks
for(int key=0; key < numberOfKeys; key++){
free(storage[key]);
}
free(storage);
hashTableKeys.clear();
return true;
}
int main(int argc, char **argv)
{
/*
* checking if memory is freed
*/
int numberOfModelKeys = 1000000;
// construct arbitrary keys
std::vector<uint64_t> hashTableKeys;
for (int i = 0; i < numberOfModelKeys ; i++){
uint64_t hashKey = static_cast<uint64_t>(i);
hashTableKeys.push_back(hashKey);
}
problematic_function(hashTableKeys);
/*
* at this point the occupied memory of the program (as shown in ubuntu's system-monitor)
* is still about 30 MiB, although it probably should be a lot less.
*/
}
char**
, когда вы показали, что хотите и можете использовать какstd::vector
, так иstd::string
. - person François Andrieux   schedule 20.02.2019numberOfKeys
этоdouble
? - person NathanOliver   schedule 20.02.2019(storage[key]!=nullptr
когда-либо равноtrue
, вы не сможетеfree
выполнить любые предыдущие распределения, которые вы ранее выполняли в своей функции. - person François Andrieux   schedule 20.02.2019free
ing память не обязательно означает, что она сразу возвращается в ОС. Приложение может по-прежнему владеть правами на эти страницы памяти, чтобы ускорить выделение памяти в будущем. Таким образом, освобожденная память может по-прежнему отображаться как используемая с точки зрения ОС. - person François Andrieux   schedule 20.02.2019char **
? - person doctorlove   schedule 20.02.2019std::size_t
. Использование двойного числа является неправильным подходом, и если число действительно велико, вы получите неправильный результат, поскольку оно может точно представлять только целые числа размером 53 бита.std::size_t
, с другой стороны, гарантированно работает. - person NathanOliver   schedule 20.02.2019key
(индексы вашего цикла) наsize_t
, так какint
может быть меньше, чемsize_t
. - person NathanOliver   schedule 20.02.2019int
, то вашиfor
циклы все равно не будут работать. - person François Andrieux   schedule 20.02.2019data()
std::vector<char*>
этоchar**
. Затем вы можете построить этот вектор, назначивdata()
каждого элемента вstd::vector<std::string>
. - person François Andrieux   schedule 20.02.2019std::vector
является то, что все элементы гарантированно хранятся в непрерывном массиве, а членdata()
std::vector<T>
всегда возвращаетT*
(за исключениемstd::vector<bool>
по глупым причинам). Вместо этого его можно использовать всякий раз, когда вы можете использовать динамически выделяемый массив. - person François Andrieux   schedule 20.02.2019