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

Freeing memory in an embedded application won't help in reducing virtual storage

本文关键字:无助于 虚拟存储 内存 嵌入式 应用程序 释放      更新时间:2023-10-16

我安装的嵌入式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-有时我使用用new初始化的fstream*,我认为这不会有任何区别,因为C++对象一旦超出范围就会被销毁。

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

注意:源代码很大,这些是应用程序使用最多的数据结构。如果有任何其他可疑的事情,我会更新

我使用SSH编译应用程序并将其移动到嵌入式设备,运行应用程序并监控top命令输出;应用程序进程的VSZ值一直在增加,直到像11K这样的大值和系统崩溃。我确信我所做的每一次分配都有相应的空闲机制(free, delete等)。

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

感谢您的帮助。我可以立即获得任何需要的信息。提前感谢!

更新8/4/2015:增加应用程序VSZ的过程是不断收集数据并将其存储在闪存上的文件中,有一种机制可以检查是否超过大小,但我现在不使用它。这可能有关系吗?

绝对没有理由期望delete/free将虚拟内存返回到系统——他们通常会将其保留在进程中,以便以后重用。一些分配模式将导致增长,即使由于免费存储碎片而没有泄漏。

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

如果仍然需要的话,下一步是使用专门的分配器:固定大小的对象分配器(消除碎片并最大限度地减少开销),用于具有已知生存期的对象(无论大小)的竞技场分配器,以及用于显式、确定性地将VM返回到操作系统的基于mmap的后备存储。

请注意,您确实有一个内置的arena分配器可用——它用于具有自动作用域的局部变量。使用它而不是new——在适用的情况下——可以让生活变得更简单。

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;
}

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

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);
}