有时只得到 jni segv_accer或segv_mapper错误

Getting jni segv_accer or segv_mapper error sometimes only

本文关键字:segv accer mapper 错误 jni      更新时间:2023-10-16

我有以下C++代码,由网络服务器通过JNI调用。

static shared_ptr<multimap<string,SomeObject> > cacheMap;
void Cache::refresh(multimap<string, SomeObject>  delta){
shared_ptr<multimap<string, SomeObject> >  old_cache=atomic_exchange(&cacheMap,make_shared<multimap<string,SomeObject> >(delta));
shared_ptr<multimap<string, SomeObject> > old_readMap=atomic_load(&old_cache);
if(old_readMap){
for(std::multimap<string, SomeObject>::iterator it = old_readMap->begin(); it != old_readMap->end(); it++){
it->second.getSomeObject()->~SomeObject();
}
old_readMap->clear();
}
}

list<int>  Cache::get(string key1,const char* key2){
SomeObject value;
list<int> IDs;
try{
shared_ptr<multimap<string,SomeObject> > readMap=atomic_load(&cacheMap);
pair<mapIterator,mapIterator> result=readMap->equal_range(key1);
for(auto iterator=result.first; iterator!=result.second; iterator++){
value=iterator->second;
if(!(value.getSomeObject()->test(key2,strlen(key2)))){
IDs.push_front(value.getInternalID());
}
}
}
catch(...){
std::exception_ptr p = std::current_exception();
std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << " from Cache.cpp " << std::endl;
}
return IDs;
}

缓存映射将由 cronjob 每 5 分钟刷新一次,请求线程通过 get(( 继续访问缓存。这是一个多线程环境。一切正常,3 或 4 天后我收到此 SEGV_ACCER/SEGV_MAPPER错误,转储如下所示 (转储中的几行(

# Problematic frame:
# C  [libstdc++.so.6+0xd7172]  std::string::assign(std::string const&)+0x12
...
Stack: [0x00007fed854c2000,0x00007fed855c3000],  sp=0x00007fed855c08b0,  free space=1018k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libstdc++.so.6+0xd7172]  std::string::assign(std::string const&)+0x12
C  [libCustomCache.so+0x1c0b0]  Cache::get(std::string, char const*)+0x122

我已经使用shared_ptr和原子操作来确保线程安全,但仍然收到此错误。关于如何调试它的任何想法?

Cache::refreshCache::get竞相同时销毁和读取相同的SomeObject对象。这是一个竞争条件。

这里的原子指针或std::shared_ptr的原子用法仅使指针的值原子化且无种族,而不是指针引用的对象。

一种可靠的方法是使用 C++17std::shared_mutex或 C++14 boost::shared_mutex 来允许读取器并发访问缓存,并且仅对写入器进行独占访问。

您还应该消除手动销毁SomeObject的需要。

例:

using namespace std;
namespace {
shared_mutex m;
multimap<string, SomeObject> cacheMap; // SomeObject doesn't need to be manually destroyed.
} // namespace 
void Cache::refresh(multimap<string, SomeObject> delta){
std::unique_lock lock(m); // Writer exclusive lock.
cacheMap = std::move(delta);
}
list<int> Cache::get(string const& key1, const char* key2) {
list<int> IDs;
std::shared_lock lock(m); // Readers shared lock.
for(auto result = readMap->equal_range(key1); result.first != result.second; ++result.first) {
auto&& value = *result.first;
if(!(value.getSomeObject()->test(key2, strlen(key2))))
IDs.push_front(value.getInternalID());
}
return IDs;
}