上週在進行壓測時,某個調用hiredis庫的函數出現了coredump,調用棧以下:git
Program terminated with signal 11, Segmentation fault. #0 0x000000000052c497 in wh::common::redis::RedisConn::HashMultiGet(std::string const&, std::vector<std::string, std::allocator<std::string> > const&, std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >&) () (gdb) bt #0 0x000000000052c497 in wh::common::redis::RedisConn::HashMultiGet(std::string const&, std::vector<std::string, std::allocator<std::string> > const&, std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >&) () #1 0x00000000004cc418 in wh::server::user_activityHandler::getUserRating(wh::server::GetUserRatingResult&, std::vector<int, std::allocator<int> > const&) () #2 0x00000000004e54cf in wh::server::user_activityProcessor::process_getUserRating(int, apache::thrift::protocol::TProtocol*, apache::thrift::protocol::TProtocol*, void*) () #3 0x00000000004e3ad3 in wh::server::user_activityProcessor::dispatchCall(apache::thrift::protocol::TProtocol*, apache::thrift::protocol::TProtocol*, std::string const&, int, void*) ()
RedisConn
中的HashMultiGet
代碼以下:github
int RedisConn::HashMultiGet( const string& key, const vector<string>& fields, map<string, string>& fvs) { if(key.empty() || fields.empty()) return 0; if ( !conn_ ) { LOG(LOG_ERR, "ERROR!!! conn is NULL!!!"); return kErrConnBroken; } size_t argc = fields.size() + 2; const char* argv[argc]; //在棧中直接分配內存 size_t argvlen[argc]; std::string cmd = "HMGET"; argv[0] = cmd.data(); argvlen[0] = cmd.length(); argv[1] = key.data(); argvlen[1] = key.length(); size_t i = 2; for(vector< string >::const_iterator cit = fields.begin(); cit != fields.end(); ++cit ) { // put value into arg list argv[i] = cit->data(); argvlen[i] = cit->length(); ++i; } redisReply* reply = static_cast<redisReply*>( redisCommandArgv( conn_, argc, argv, argvlen ) ); if ( !reply ) { this->Release(); LOG(LOG_ERR, "ERROR!!! Redis connection broken!!!"); return kErrConnBroken; } int32_t ret = kErrOk; if ( reply->type != REDIS_REPLY_ARRAY ) { this->CheckReply( reply ); LOG(LOG_ERR, "RedisReply ERROR: %d %s", reply->type, reply->str); ret = kErrUnknown; } ...
其中出現問題的地方是構造hiredis
的redisCommandArgv
請求時,構造的兩個參數都是直接在棧上分配。redis
const char* argv[argc]; //在棧中直接分配內存 size_t argvlen[argc];
壓測時,HashMultiGet(key, fields, fvs)
中fields
大小超過10萬,那麼在棧上分配的內存爲 10萬 * (8 + 8) = 160萬字節 = 1.6MB (64位系統),再加上以前分配的棧,將棧打爆了,致使了coredump.apache
爲何要將參數在棧上分配呢?一種多是:若是在堆上分配,就須要考慮free的問題。less
解決方法:
將argv和argvlen在堆上分配,畢竟堆的大小比棧大不少。函數