释放嵌入式应用程序中的内存无助于减少虚拟存储

时间:2015-04-08 10:06:31

标签: c++ c memory-management

我所拥有的嵌入式Linux系统有28K RAM和31.6M的闪存文件系统。我开发了一个需要在嵌入式Linux中持续运行的应用程序。问题是应用程序的虚拟存储大小(top命令中的VSZ)不断增加,直到系统崩溃。如果我理解正确并纠正我如果我错了,VSZ应该根据程序完成的内存分配而有所不同,如果内存被释放,它应该转到之前的值并保持不变。

程序在源代码中使用以下声明:

1-结构指针的向量:

vector<Struct*> someVector; // Struct pointers are initialized with new

// After the previous vector has some values, it is freed like this
for(unsigned i = 0; i < someVector.size(); i++)
{
    delete someVector[i];
}
someVector.clear();
vector<Struct*>().swap(someVector);

2-一个字符串向量,与之前相同但不是循环内的deletesomeVector[i] = "";

3- char*

char* somePointer = (char*) malloc(100);
free(somePointer);
somePointer = NULL;

4-有时我使用fstream*初始化new我不认为它会产生任何影响,因为C ++对象一旦超出范围就会被销毁。

5- char** array = new char*[100];这被delete[] array删除。我在内部元素上使用了deletevalgrind给了我Mismatched free/delete或类似内容。

注意:源很大,这些是应用程序使用的最多数据结构。如果还有其他可疑之处,我会做更新

我编译应用程序并使用SSH将其移动到嵌入式设备,我运行应用程序并监视top命令输出;应用程序进程的VSZ值不断增加,直到像11K这样的大值并且系统崩溃。我很确定每次分配我都有相应的免费机制(free, delete等)。

valgrind ./myApplication工具甚至没有显示警告消息,我是否应该假设安全地完成分配和释放?

感谢任何帮助。我可以立即获得所需的任何信息。在此先感谢!

2015年8月4日更新:增加应用程序VSZ的过程是收集数据并将它们连续存储在闪存中的文件中,有一种机制可以检查超出的大小,但我现在不使用它。这可能是相关的吗?

3 个答案:

答案 0 :(得分:2)

绝对没有理由期望删除/免费将虚拟内存返回给系统 - 它们通常会将其保留在进程中以供以后重复使用。一些分配模式即使没有因免费存储碎片而导致泄漏也会导致增长。

第一步仍然是确保你没有泄漏,既使用valgrind,又在可能的情况下在智能指针控制下移动这些动态分配,并使用valgrind的massif工具查看你分配的内存的去向(这将有助于识别像luk32提到的问题。)

下一步,如果仍然需要,则使用专门的分配器:固定大小的对象分配器(消除碎片并最小化开销),具有众所周知的生命周期的对象(无论大小)的竞技场分配器,以及基于mmap的支持商店以明确,确定地将VM返回到操作系统。

请注意,您确实已经有一个内置的竞技场分配器 - 它用于具有自动范围的局部变量。使用此代替new所有内容 - 在适用的情况下 - 使生活变得更加简单。

答案 1 :(得分:0)

someVector[i] = "";这并不一定意味着将修剪内部缓冲区。您可以使用capacity()进行检查。在c ++ 11中有shrink_to_fit,其他方法似乎不起作用。

#include <iostream>
using namespace std;

int main() {
    string s("Some example string. Let's give it few more bytes.");
    cout << s.size() << '\n';
    cout << s.capacity() << '\n';
    s = "";
    cout << s.capacity() << '\n';
    s.clear();
    cout << s.capacity() << '\n';
    s.resize(0);
    cout << s.capacity() << '\n';
    s.shrink_to_fit();
    cout << s.capacity() << '\n';
    return 0;
}

在ideone:http://ideone.com/nwIzYz上为50以外的所有方法提供shrink_to_fit。它也不会被valgrind报告为“丢失”。因此,在删除这些对象之前,它们将保留在其内部缓冲区中。如果你在某个全局范围内使用它,然后尝试用这些调用释放内存,它很可能无法工作。

答案 2 :(得分:0)

New/delete在内部使用malloc/free。这两个函数都是围绕内核函数的包装器,如mmapbkr/sbrk(在linux上)。这些函数会跟踪页面,以便在完成大量小分配的情况下优化内存碎片。

当您调用free时,这些页面可能不会返回到操作系统,当您查询操作系统的内存时,操作系统将不会给您内存,直到使用内存或看起来像你打算用它。

如果要将内存返回到操作系统,在Linux上,可以使用malloc_trim

我在c ++ 03编译器上使用此方法缩小以适应。

template<typename T, class Allocator>
void shrink_capacity(std::vector<T,Allocator>& m)
{
    std::vector<T,Allocator>(m.begin(),m.end()).swap(m);
}