提升进程间向量不释放共享内存
boost interprocess vector does not deallocate shared memory
我正在使用 boost::interprocess 在 linux 上的进程之间共享复杂的数据结构。它大部分工作,但我的共享内存在每次更新共享数据时慢慢泄漏。
经过一些调试后,我能够想出相对较短的方法来重现此行为:
#include <iostream>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
using UniversalAllocator = boost::interprocess::allocator
< void
, boost::interprocess::managed_shared_memory::segment_manager >;
using CharAllocator = boost::interprocess::allocator
< char
, boost::interprocess::managed_shared_memory::segment_manager >;
using ShmString = boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator>;
struct Struct1
{
Struct1(UniversalAllocator allocator)
: member(allocator)
{}
struct Struct2
{
Struct2(UniversalAllocator allocator)
: vector_member(allocator)
{}
struct Struct3
{
Struct3(UniversalAllocator allocator)
: first(allocator)
, second(allocator)
{}
ShmString first;
ShmString second;
};
using Struct3Allocator = boost::interprocess::allocator
< Struct3, boost::interprocess::managed_shared_memory::segment_manager >;
using Structs3 = boost::interprocess::vector<Struct3, Struct3Allocator>;
Structs3 vector_member;
} member;
};
using Struct1Allocator = boost::interprocess::allocator
< Struct1, boost::interprocess::managed_shared_memory::segment_manager >;
using Struct1Vector = boost::interprocess::vector
< Struct1, Struct1Allocator>;
int main(void)
{
boost::interprocess::managed_shared_memory segment(
boost::interprocess::create_only,
"TEST_MEMORY_LEAK",
1500);
std::cout << segment.get_free_memory() << std::endl;
while(1)
{
Struct1Vector svector(segment.get_segment_manager());
Struct1 selement(segment.get_segment_manager());
svector.push_back(selement);
std::cout << segment.get_free_memory() << std::endl;
}
return 0;
}
内存在 push_back
调用内部分配,但在离开范围时仅部分释放。结果:
$ g++ --std=c++11 -Wall -pthread -c memory_leak.cpp -o memory_leak.o
$ g++ memory_leak.o -o memory_leak -pthread -lrt
$ ./memory_leak
1276
1180
1132
1084
1036
988
940
892
844
796
748
700
652
604
556
508
460
412
364
316
268
220
172
124
76
28
terminate called after throwing an instance of 'boost::interprocess::bad_alloc'
what(): boost::interprocess::bad_alloc
Aborted
奇怪的是,如果我将共享内存大小替换为 1000(而不是 1500),循环真的是无穷无尽的(它最终会打印 24 无限次,所以内存泄漏到最后一刻然后......停止?)。
我正在使用 boost 1.54 和 gcc 4.8.4,如果有任何帮助,我将不胜感激,我有点 运行 没主意:(
共享内存不像堆,但也不是你的堆。共享意味着锁定,而锁定是昂贵的。您会注意到 managed_buffer/managed_mapped_file/managed_shared_memory 段管理器将尽可能晚地回收内存(仅当分配失败时才可能)。
如果此时空闲内存开销太小,则可能没有足够的空间来满足连续分配(因此您会预料到分配失败,作为泄漏的证据。实际上它是碎片的证据).
我继续实施我自己的内存管理算法(作为 rbtree_best_fit 的精简包装器,这是默认的,因此在上面的示例中使用)。我最终看到上面的代码在 push_back 上分配了两个段 - 一个非零长度和一个零长度并且只取消分配前一个。这对我来说似乎不对,所以我在 boost 网站上搜索了解释,发现我认为是 issue。将系统提升到 1.55 后,上面的示例无限次打印 1228(可能是正确的行为)。
我正在使用 boost::interprocess 在 linux 上的进程之间共享复杂的数据结构。它大部分工作,但我的共享内存在每次更新共享数据时慢慢泄漏。
经过一些调试后,我能够想出相对较短的方法来重现此行为:
#include <iostream>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
using UniversalAllocator = boost::interprocess::allocator
< void
, boost::interprocess::managed_shared_memory::segment_manager >;
using CharAllocator = boost::interprocess::allocator
< char
, boost::interprocess::managed_shared_memory::segment_manager >;
using ShmString = boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator>;
struct Struct1
{
Struct1(UniversalAllocator allocator)
: member(allocator)
{}
struct Struct2
{
Struct2(UniversalAllocator allocator)
: vector_member(allocator)
{}
struct Struct3
{
Struct3(UniversalAllocator allocator)
: first(allocator)
, second(allocator)
{}
ShmString first;
ShmString second;
};
using Struct3Allocator = boost::interprocess::allocator
< Struct3, boost::interprocess::managed_shared_memory::segment_manager >;
using Structs3 = boost::interprocess::vector<Struct3, Struct3Allocator>;
Structs3 vector_member;
} member;
};
using Struct1Allocator = boost::interprocess::allocator
< Struct1, boost::interprocess::managed_shared_memory::segment_manager >;
using Struct1Vector = boost::interprocess::vector
< Struct1, Struct1Allocator>;
int main(void)
{
boost::interprocess::managed_shared_memory segment(
boost::interprocess::create_only,
"TEST_MEMORY_LEAK",
1500);
std::cout << segment.get_free_memory() << std::endl;
while(1)
{
Struct1Vector svector(segment.get_segment_manager());
Struct1 selement(segment.get_segment_manager());
svector.push_back(selement);
std::cout << segment.get_free_memory() << std::endl;
}
return 0;
}
内存在 push_back
调用内部分配,但在离开范围时仅部分释放。结果:
$ g++ --std=c++11 -Wall -pthread -c memory_leak.cpp -o memory_leak.o
$ g++ memory_leak.o -o memory_leak -pthread -lrt
$ ./memory_leak
1276
1180
1132
1084
1036
988
940
892
844
796
748
700
652
604
556
508
460
412
364
316
268
220
172
124
76
28
terminate called after throwing an instance of 'boost::interprocess::bad_alloc'
what(): boost::interprocess::bad_alloc
Aborted
奇怪的是,如果我将共享内存大小替换为 1000(而不是 1500),循环真的是无穷无尽的(它最终会打印 24 无限次,所以内存泄漏到最后一刻然后......停止?)。
我正在使用 boost 1.54 和 gcc 4.8.4,如果有任何帮助,我将不胜感激,我有点 运行 没主意:(
共享内存不像堆,但也不是你的堆。共享意味着锁定,而锁定是昂贵的。您会注意到 managed_buffer/managed_mapped_file/managed_shared_memory 段管理器将尽可能晚地回收内存(仅当分配失败时才可能)。
如果此时空闲内存开销太小,则可能没有足够的空间来满足连续分配(因此您会预料到分配失败,作为泄漏的证据。实际上它是碎片的证据).
我继续实施我自己的内存管理算法(作为 rbtree_best_fit 的精简包装器,这是默认的,因此在上面的示例中使用)。我最终看到上面的代码在 push_back 上分配了两个段 - 一个非零长度和一个零长度并且只取消分配前一个。这对我来说似乎不对,所以我在 boost 网站上搜索了解释,发现我认为是 issue。将系统提升到 1.55 后,上面的示例无限次打印 1228(可能是正确的行为)。