我所拥有的嵌入式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-一个字符串向量,与之前相同但不是循环内的delete
:someVector[i] = "";
3- char*
char* somePointer = (char*) malloc(100);
free(somePointer);
somePointer = NULL;
4-有时我使用fstream*
初始化new
我不认为它会产生任何影响,因为C ++对象一旦超出范围就会被销毁。
5- char** array = new char*[100];
这被delete[] array
删除。我在内部元素上使用了delete
但valgrind
给了我Mismatched free/delete
或类似内容。
注意:源很大,这些是应用程序使用的最多数据结构。如果还有其他可疑之处,我会做更新
我编译应用程序并使用SSH将其移动到嵌入式设备,我运行应用程序并监视top
命令输出;应用程序进程的VSZ值不断增加,直到像11K这样的大值并且系统崩溃。我很确定每次分配我都有相应的免费机制(free, delete
等)。
valgrind ./myApplication
工具甚至没有显示警告消息,我是否应该假设安全地完成分配和释放?
感谢任何帮助。我可以立即获得所需的任何信息。在此先感谢!
2015年8月4日更新:增加应用程序VSZ的过程是收集数据并将它们连续存储在闪存中的文件中,有一种机制可以检查超出的大小,但我现在不使用它。这可能是相关的吗?
答案 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
。这两个函数都是围绕内核函数的包装器,如mmap
或bkr/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);
}