cmake:动态链接库(so)中静态链接tcmalloc(gperftools2.4)暨静态链接libstdc++

来源:互联网 发布:汕头淘宝仓库出租 编辑:程序博客网 时间:2024/04/30 21:29

将tcmalloc作为动态库使用,非常方便,网上有很多资料介绍了。tcmalloc.a也可以以静态链接的方式加入应用程序中,大概因为使用太方便,网上关于这方面的介绍都是一笔带过,但是如果要在动态 库(so)中静态编译tcmalloc,却是有所不同的。
我的项目中有一个so动态库,需要在java中通过jni调用,因为涉及频繁的内存分配操作所以这个so希望用tcmalloc管理内存池以提高系统运行效率,如果使用以动态库方式使用tcmalloc。那么在应用服务器(tomcat)启动的时候,需要先设置LD_PRELOAD参数指向tcmalloc.so,然后执行startup.sh启动tomcat。这样以来,不仅是我的so库,整java程序在运行过程中的所有向操作系统申请释放内存的过程都交给了tcmalloc管理了,其实挺好的。使用这种方案,我的so库代码不需要在编译时链接tcmalloc,什么都不用改变,就能使用tcmalloc。
但是凡事有利就有弊,这个方案带的成本就是在系统安装、维护时稍显复杂:需要在服务器上安装tcmalloc和libunwind(应用系统运行在64位操作系统下),还可能需要修改tomcat启动脚本以加入LD_PRELOAD参数,对工程实施人员的要求比较高。

于是我觉得用静态链接方式将tcmalloc编译到so库中比较好,这样这个动态库以比较独立的方式发行,不再依赖系统中是否安装了tcmalloc和libunwind。应用服务器启动脚本也不需要做更多修改。
下面是我的CMakeLists.txt中关于静态连接tcmalloc和libstdc++的代码。(so的代码是以C++11写的,所以还要依赖于libstdc++库,所以我打算把libstdc++库也以静态方式连接到程序中)

##判断操作系统类型if(CMAKE_SYSTEM_NAME MATCHES "Linux")# 新版本编译器要用 -pthread 而不是 -lpthread# 否则编译时会报错找不到pthread_atfork “undefined reference to pthread_atfork”    target_link_libraries(cmimpl -pthread )    #######静态链接c++库###################    SET_TARGET_PROPERTIES(cmimpl PROPERTIES  LINK_FLAGS "-static-libstdc++")    ###这里的参数参见我的另一篇博文 [《gcc下使用tcmalloc(gperftools)2.4的注意事项》](http://blog.csdn.net/10km/article/details/50401005)    set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free" )    #######加入 tcmalloc 内存池支持(动态链接) #######    #target_link_libraries(cmimpl tcmalloc_minimal)    #message(STATUS "tcmalloc(shared) support added")    #######linux 下加入 tcmalloc 内存池支持(静态链接) #######    target_link_libraries(cmimpl tcmalloc_minimal.a)    message(STATUS "tcmalloc(static) support added")endif(CMAKE_SYSTEM_NAME MATCHES "Linux")

cmake生成的Makefile中实际的连接指令(link.txt的内容)是:

/usr/local/bin/g++ -fPIC -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free -O3 -DNDEBUG -static-libstdc++ -shared …… -pthread -Wl,-Bstatic -ltcmalloc_minimal -Wl,-Bdynamic

一切就绪,重新编译代码,然后就是报错。

/usr/local/bin/g++  -fPIC -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free -O3 -DNDEBUG -static-libstdc++ -shared -Wl,-soname,libcmimpl.so.1 -o ../lib/libcmimpl.so.1.0 CMakeFiles/cmimpl.dir/OverTableManager.cpp.o CMakeFiles/cmimpl.dir/CodeMgrUtils.cpp.o CMakeFiles/cmimpl.dir/HashMapCl.cpp.o CMakeFiles/cmimpl.dir/ICodeManager.cpp.o CMakeFiles/cmimpl.dir/ICodeManagerCPU.cpp.o CMakeFiles/cmimpl.dir/CodeManagerFactory.cpp.o CMakeFiles/cmimpl.dir/TopKCodeBean.cpp.o CMakeFiles/cmimpl.dir/RWLock.cpp.o CMakeFiles/cmimpl.dir/ThreadPool.cpp.o -lpthread -lpthread -Wl,-Bstatic -ltcmalloc_minimal -Wl,-Bdynamic /usr/bin/ld: /usr/local/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../libtcmalloc_minimal.a(libtcmalloc_minimal_la-tcmalloc.o): relocation R_X86_64_32 against `.rodata.str1.8' can not be used when making a shared object; recompile with -fPICgmake[3]: Leaving directory `/home/hadoop/workspace/codemgr.prj'/usr/local/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../libtcmalloc_minimal.a: could not read symbols: Bad value

大意就是需要用-fPIC参数重新编译tcmalloc,网上找了很多关于”can not be used when making a shared object; recompile with -fPIC”问题的文章(关于-fPIC参数,这个文章讲得挺详细《译与链接的问题 gcc -fPIC -shared》),解决这个问题的方法也大同小异,就是根据这个错误提示用-fPIC参数重新编译相关的库,这里是就是指要重新编译tcmalloc。
于是就用网上介绍的办法,重新编译tcmalloc,在gperftools2.4源代码目录下执行:

./configure CXXFLAGS=-fPIC
make
make install

然后再重新编译so,就通过了。

总结

如果在可执行程序中静态链接tcmalloc时,用默认参数编译tcmalloc就好了,无需带-fPIC参数,
但是在动态库(so)中静态链接tcmalloc,必须要用-fPIC重新编译tcmalloc。

0 0
原创粉丝点击