Comments (33)
rpc_byte_stream的引用计数有问题? 导致对象析构?
from sofa-pbrpc.
Hi @gandalf000
能不能提供下你用的版本,或者看看最新的主干代码会不会有这个问题(之前版本io_service和socket的释放顺序有些问题,新版已经调整了)
from sofa-pbrpc.
·@cyshi 今天同样遇到了这个问题,core的位置跟上面的同学一模一样,sofa-pbrpc的版本为1.0.0
等下我看看最新的版本
from sofa-pbrpc.
@ysh @gandalf000 我试了下,大体情况如下(拿tera源码作实验,出现core的是编译后产生的teracli二进制,表现为可以正常运行,但是在全局析构函数中,core在上述位置):
(1)在ubumtu 14.04发行版下,无论使用哪个版本的sofa-pbrpc,均会在上述地方core。
(2)同样版本的源码,在ubuntu 14.10下,没有任何问题。
(3)ldd显示,teracli所依赖的动态链接库中,libstdc++的版本有所不同,在可以正常运行的ubuntu14.10中,libstdc++的版本号为6.0.20,而在core的ubuntu14.04下,libstdc++的版本号为6.0.19。
(4)将ubuntu14.10中的6.0.20版本复制到ubuntu14.04中,动态加载时用LDD_PRELOAD指定使用6.0.20版本,可恢复正常运行。
所以看起来像是一些库版本之间的兼容性问题
.
from sofa-pbrpc.
Hi @yvxiang 新版中我只修了server,你可以在 rpc_client_impl.cc 中尝试调整Stop()
函数的_work_thread_group->stop();
这句到ClearStreams()
后面,看看是否还会core
from sofa-pbrpc.
@cyshi 还是会core的,在析构全局变量,调用RpcClientImpl::Stop()时core了。如果把RpcClient::~RpcClient()中的ShutDown()去掉,让Stop()在RpcClientImpl析构时执行,就没问题了。
基本上所有地方都是shared_ptr,想不通为啥……
from sofa-pbrpc.
@yvxiang 是否可以弄一个简单的sample code来让我在ubuntu 14.04下面重现这个core?而不需要编译teracli
from sofa-pbrpc.
@qinzuoyan 可以用sample/echo这个作为例子:
(1) 不作任何改动时,可以正常运行。
(2) 将rpc_client这个main函数内的局部变量改为全局变量时,会出现core。dump出来的结果显示,是在RpcByteStream::close()中调用shutdown时,线程池中的线程挂了。
(3) 如果在main函数结束之前,手动调用一下全局rpc_client的Shutdown() 函数,则不会core。
(4) teracli中,正是有一个全局的静态变量m_rpc_client,所以和这里的情况一样。
这里 提到了由于boost的原因可能导致类似的错误,但是还不完全一样。
难道全局析构会有什么不同吗……
from sofa-pbrpc.
查了许久也没有找到根本原因,不过有个简单的修复办法,参见 #47 。另外目前还是不要轻易修改析构函数中的顺序吧,怕引出新的问题。
from sofa-pbrpc.
按 @yvxiang 给的复现方法,现在基本能确认是全局变量析构顺序导致程序coredump
第一个全局变量是 rpc_client
,第二个比较隐蔽是 boost error.hpp中的misc_category
ubuntu下程序coredump是因为先构造了rpc_client
,之后构造了 misc_category
,所以析构的时候misc_category
先于rpc_client
释放,rpc_client->Stop()
的过程中(主线程中),asio的IO线程被唤醒处理错误,这时拿到的error中的m_cat(就是misc_category)实际已经被释放过,虚函数表被清空,所以程序异常退出
所以要修复这个问题,就要保证misc_category
先于rpc_client
构造,有一种改法是将<boost/asio.hpp>
置入rpc_client.h
中,明确告诉编译器依赖关系,保证misc_category
先构造 @qinzuoyan 可以看看这样有没有问题 参见 #48
from sofa-pbrpc.
赞 @cyshi 找出了问题根源。我之前也一直按照全局变量析构顺序的方向追,但是只考虑到boost::system::system_category和boost::system::generic_category(这两者的析构顺序没有问题),并没有想到是boost::asio::error里面的category的析构顺序,所以百思不得其解,多谢@cyshi 帮我解了这个心头之结。
@cyshi 的修复方式 #48 确实能解决这个问题,但是我觉得带来一个新的问题,就是sofa-pbrpc对外的头文件将依赖boost。
目前,sofa-pbrpc的头文件和库都完全不依赖boost:
- 对于头文件,所有对用户暴露的头文件都不引用boost的头文件,为此还专门把boost的smart_ptr剥离出来(参见src/sofa/pbrpc/smart_ptr)
- 对于库文件,为了避免唯一可能的依赖libboost_system.a,专门把boost_system_error_code.cc编译到里libsofa-pbrpc.a中(参见src/sofa/pbrpc/boost_system_error_code.cc)
我修改了demo下面的Makefile,可以看到对boost的头文件和库都是完全无依赖的。
所以,为了保持这一点,我觉得这样修改可能更好:
- 在RpcClient和RpcServer的构造函数中调用touch_boost_error_category()来影响全局变量的构建顺序,通过测试,确实可行
- 在RpcMessageStream的on_read_some()和on_write_some()中检查是否is_connected(),虽然这里对解决该问题其实已经不是必要的,但是加上也是合理的
参见pull request:#47
from sofa-pbrpc.
@qinzuoyan 的修复方式更合理 merged
from sofa-pbrpc.
赞~
from sofa-pbrpc.
merge了48的改动之后,发现还是一样的core dump。
from sofa-pbrpc.
@gandalf000 可以稳定复现吗?
from sofa-pbrpc.
387 #0 0x00007f40a684f625 in raise () from /lib64/libc.so.6
388 #1 0x00007f40a6850e05 in abort () from /lib64/libc.so.6
389 #2 0x00007f40a70aaa55 in __gnu_cxx::__verbose_terminate_handler () at ../../.././libstdc++-v3/libsupc++/vterminate.cc:95
390 #3 0x00007f40a70a8bf6 in __cxxabiv1::__terminate (handler=) at ../../.././libstdc++-v3/libsupc++/eh_terminate.cc:38
391 #4 0x00007f40a70a8c23 in std::terminate () at ../../.././libstdc++-v3/libsupc++/eh_terminate.cc:48
392 #5 0x00007f40a70a96df in __cxxabiv1::__cxa_pure_virtual () at ../../.././libstdc++-v3/libsupc++/pure.cc:50
393 #6 0x00000000005c44e5 in sofa::pbrpc::RpcMessageStreamsofa::pbrpc::shared_ptr<sofa::pbrpc::RpcControllerImpl >::on_read_some(boost::system::error_code const&, unsigned long) ()
394 #7 0x00000000005b24e0 in boost::asio::detail::reactive_socket_recv_op<boost::asio::mutable_buffers_1, boost::bi::bind_t<void, boost::mfi::mf2<void, sofa::pbrpc::RpcByteStream, boost::system::error_code const&, unsigned long>, boo st::bi::list3boost::bi::value<sofa::pbrpc::shared_ptr<sofa::pbrpc::RpcByteStream >, boost::arg<1>, boost::arg<2> > > >::do_complete(boost::asio::detail::task_io_service, boost::asio::detail::task_io_service_operation, boost::s ystem::error_code const&, unsigned long) ()
395 #8 0x00000000005b4fb9 in boost::asio::detail::epoll_reactor::descriptor_state::do_complete(boost::asio::detail::task_io_service, boost::asio::detail::task_io_service_operation, boost::system::error_code const&, unsigned long) ()
396 #9 0x00000000005b793e in boost::asio::detail::task_io_service::run(boost::system::error_code&) ()
397 #10 0x00000000005b82ae in sofa::pbrpc::ThreadGroupImpl::thread_run(void*) ()
398 #11 0x00007f40a77cf9d1 in start_thread () from /lib64/libpthread.so.0
399 #12 0x00007f40a69058fd in clone () from /lib64/libc.so.6
发生的概率还挺大的。
from sofa-pbrpc.
看堆栈,应该是这个rpc_byte_stream被析构了?
from sofa-pbrpc.
用debug模式吧
from sofa-pbrpc.
开了DEBUG模式。
#0 0x00007f33d2b75625 in raise () from /lib64/libc.so.6
#1 0x00007f33d2b76e05 in abort () from /lib64/libc.so.6
#2 0x00007f33d33d0a55 in __gnu_cxx::__verbose_terminate_handler () at ../../.././libstdc++-v3/libsupc++/vterminate.cc:95
#3 0x00007f33d33cebf6 in __cxxabiv1::__terminate (handler=) at ../../.././libstdc++-v3/libsupc++/eh_terminate.cc:38
#4 0x00007f33d33cec23 in std::terminate () at ../../.././libstdc++-v3/libsupc++/eh_terminate.cc:48
#5 0x00007f33d33cf6df in __cxxabiv1::__cxa_pure_virtual () at ../../.././libstdc++-v3/libsupc++/pure.cc:50
#6 0x00000000005a9b0b in boost::system::error_code::message (this=0x7f33c8f94a60) at ../../boost_1_53_0/boost/system/error_code.hpp:350
#7 0x00000000005dee6f in sofa::pbrpc::RpcMessageStreamsofa::pbrpc::shared_ptr<sofa::pbrpc::RpcControllerImpl >::on_read_some (this=0x7f339c0b5600, error=..., bytes_transferred=0)
at src/sofa/pbrpc/rpc_message_stream.h:237
#8 0x00000000005dd197 in boost::_mfi::mf2<void, sofa::pbrpc::RpcByteStream, boost::system::error_code const&, unsigned long>::callsofa::pbrpc::shared_ptr<sofa::pbrpc::RpcByteStream, boost::system::error_code const, unsigned long> (this=0x7f33c8f94a40, u=..., b1=..., b2=@0x7f33c8f94850: 0) at ../../boost_1_53_0/boost/bind/mem_fn_template.hpp:271
#9 0x00000000005dcf15 in boost::_mfi::mf2<void, sofa::pbrpc::RpcByteStream, boost::system::error_code const&, unsigned long>::operator()sofa::pbrpc::shared_ptr<sofa::pbrpc::RpcByteStream > (
this=0x7f33c8f94a40, u=..., a1=..., a2=0) at ../../boost_1_53_0/boost/bind/mem_fn_template.hpp:286
#10 0x00000000005dca58 in boost::_bi::list3boost::_bi::value<sofa::pbrpc::shared_ptr<sofa::pbrpc::RpcByteStream >, boost::arg<1>, boost::arg<2> >::operator()<boost::_mfi::mf2<void, sofa::pbrpc::RpcByteStream, boost::system::error_code const&, unsigned long>, boost::_bi::list2<boost::system::error_code const&, unsigned long const&> > (this=0x7f33c8f94a50, f=..., a=...)
at ../../boost_1_53_0/boost/bind/bind.hpp:392
#11 0x00000000005dc674 in boost::_bi::bind_t<void, boost::_mfi::mf2<void, sofa::pbrpc::RpcByteStream, boost::system::error_code const&, unsigned long>, boost::_bi::list3boost::_bi::value<sofa::pbrpc::shared_ptr<sofa::pbrpc::RpcByteStream >, boost::arg<1>, boost::arg<2> > >::operator()<boost::system::error_code, unsigned long> (this=0x7f33c8f94a40, a1=..., a2=@0x7f33c8f94a70: 0)
at ../../boost_1_53_0/boost/bind/bind_template.hpp:102
from sofa-pbrpc.
看到了,你的RpcClient是怎么使用的?是放在全局变量里吗?
from sofa-pbrpc.
这个是rpc server 的回调还是rpc client的?
没有使用全局变量
from sofa-pbrpc.
我这个进程是一个rpc server,收消息,同时用rpc client调用其它rpc service。
from sofa-pbrpc.
我print了status_, 发现是connected状态。
from sofa-pbrpc.
这个是rpc client的调用,你的rpc client是怎么使用的?
from sofa-pbrpc.
rpc_client是一个对象的成员变量, 两个stub对象共享,main函数退出时候,直接调用的exit。没有调用任何stop和析构函数。
from sofa-pbrpc.
并且只在进程exit的时候才core,正常运行不core。
from sofa-pbrpc.
rpc_client是进程启动的时候创建的,常驻。
from sofa-pbrpc.
需要在退出之前,去调用shutdown或者析构rpc client么?
from sofa-pbrpc.
了解了,这是进程退出造成的问题:
- rpc_client是一个常驻对象,即使在exit的时候,也不会调用Shutdown()或者析构函数,其内部各种工作线程会持续运行
- 在exit时,会析构全局对象,包括boost中的各种error_category
- 当error_category析构后,rpc_client的工作线程还在运行,并且is_connected()也是true,所以会运行到on_read_some()中相关代码,存取error_category,然后出core(出core原因可参见上面的讨论)
解决办法:在main()函数结束前,通过某种办法主动调用RpcClient::Shutdown()就可以了
from sofa-pbrpc.
is_connected()的逻辑判断需要添加么?
from sofa-pbrpc.
其他都不用做,在退出前调用RpcClient::Shutdown()或者RpcClient的析构函数就可以了
from sofa-pbrpc.
RpcClient::Shutdown()了之后,这个对象就不能再使用了对吧,如果再使用看起来会core掉。
from sofa-pbrpc.
是的,最好不要重用。
RpcClient是建议长期持有的,一个进程最好只有一个实例,尽量不要频繁创建和删除。
from sofa-pbrpc.
Related Issues (20)
- sofa-server端耗时异常
- sofa-client请求超时之后不关闭tcp连接导致同一个连接上请求连续超时 HOT 1
- try_start_receive是否可以省略_receive_token
- RpcServerMessageStream和RpcMessageStream类是否可抽取公共父类
- boost async_write_some可否用async_write替换 HOT 1
- sofa-pbrpc 需要引入可配置参数
- 客户端超时设置 HOT 2
- sofa-pbrpc-client health超时
- Too many threads in sofa ,how use epoll to overlap large number of socket events HOT 2
- sofa使用snapy压缩请求体大小为100+K时解压缩出错 HOT 5
- GOOGLE_ATTRIBUTE_DEPRECATED 替换成 __attribute__((deprecated)) HOT 2
- 什么时候支持window? HOT 2
- CPU使用问题 HOT 3
- 内存问题 HOT 2
- server如何主动向client发送消息? HOT 1
- bugs on weak memory model arch.(arm/power)
- server端如何主动发消息?
- 关于volatile变量相关的问题
- 有没有这种服务互相调用的方法
- cross compile error
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sofa-pbrpc.