vs2015编译tcmalloc(gperftools2.4)

2017-01-05 20:04:53来源:CSDN作者:zuoyigexingfude人点击

第七城市

TcMalloc(Thread-CachingMalloc)是google-perftools工具中的一个内存管理库,所以一般提到tcmalloc,其实就是指使用gperftools,编译tcmalloc也就是编译gperftools。 
第一次使用tcmalloc,网上找了好多关于使用tcmalloc的文章,都讲到了如何安装,如何使用,对于编译都是一笔带过。。。但是是真正实战的时候,发现如果对tcmalloc的代码结构不熟悉,这编译tcmalloc也是不小的坑。本文不涉及安装和使用,只根据自己今天的实际经历说说如何在在windows平台用msvc(准确地说是VS2015)编译tcmalloc。

下载

首先在官网下载gperftools,下载地址为:https://github.com/gperftools/gperftools , 
我下载的是最新的:gperftools-2.4.zip

哦,忘记说了,因为GFW的原因,google.com被挡了,如果你还不会翻墙,就无法去google官网下载gperftools, 
参见下面的链接,我用文中提到的第一个也是最简单的QQ浏览器解决 
分享几个目前可用的翻墙方法,解决Google、Facebook、Youtube及Twitter等被墙问题

如下图点击”Branch”出现下拉菜单在这里选择你要下载的版本: 
这里写图片描述

编译报错

zip包下载解压后是如下图的文件结构: 
这里写图片描述 
此压缩包内含README_windows.txt说明文档,该文档包含详细使用教程。gperftools.sln则是MSVC工程文件, 
根据gperftools源码包中的README_windows.txt说明,gperftools可以在VC++ 7.1(Visual Studio 2003)或以后的版本中运行。

You can load this solution file into VC++ 7.1 (Visual Studio 2003) or 
later – in the latter case, it will automatically convert the files 
to the latest format for you. (README_windows.txt中原文)

我现在用的VisualStudio 最新版本 visual studio 2015,所以应该是可以正常编译gperftools的,于是我用VS2015打开gperftools.sln,按提示将gperftools.sln转成了vs2015格式的。 
这里写图片描述

然后按ctrl+shift+B编译整个工程。。。报出无数错误。。。

1>—— 已启动生成: 项目: libtcmalloc_minimal, 配置: Debug Win32 —— 
2>—— 已启动生成: 项目: addressmap_unittest, 配置: Debug Win32 —— 
3>—— 已启动生成: 项目: low_level_alloc_unittest, 配置: Debug Win32 —— 
4>—— 已启动生成: 项目: tcmalloc_minimal_unittest-static, 配置: Debug Win32 —— 
2> dynamic_annotations.c 
1> dynamic_annotations.c 
3> dynamic_annotations.c 
4> dynamic_annotations.c 
2>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
2> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
4>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
4> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
3>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
3> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
1>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
1> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
5>—— 已启动生成: 项目: addr2line-pdb, 配置: Debug Win32 —— 
6>—— 已启动生成: 项目: nm-pdb, 配置: Debug Win32 —— 
7>—— 已启动生成: 项目: tcmalloc_minimal_unittest, 配置: Debug Win32 —— 
8>—— 已启动生成: 项目: tcmalloc_minimal_large_unittest, 配置: Debug Win32 —— 
6> nm-pdb.c 
5> addr2line-pdb.c 
8> tcmalloc_large_unittest.cc 
7> testutil.cc 
6>c:/program files (x86)/windows kits/8.1/include/um/dbghelp.h(1544): warning C4091: “typedef ”: 没有声明变量时忽略“”的左侧 
6>c:/program files (x86)/windows kits/8.1/include/um/dbghelp.h(3190): warning C4091: “typedef ”: 没有声明变量时忽略“”的左侧 
6>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/nm-pdb.c(113): warning C4474: printf: 格式字符串中传递的参数太多 
6> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/nm-pdb.c(113): note: placeholders and their parameters expect 1 variadic arguments, but 2 were provided 
5>c:/program files (x86)/windows kits/8.1/include/um/dbghelp.h(1544): warning C4091: “typedef ”: 没有声明变量时忽略“”的左侧 
5>c:/program files (x86)/windows kits/8.1/include/um/dbghelp.h(3190): warning C4091: “typedef ”: 没有声明变量时忽略“”的左侧 
6>nm-pdb.obj : warning LNK4075: 忽略“/EDITANDCONTINUE”(由于“/SAFESEH”规范) 
5>addr2line-pdb.obj : warning LNK4075: 忽略“/EDITANDCONTINUE”(由于“/SAFESEH”规范) 
7>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
7> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
7> tcmalloc_unittest.cc 
8>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): error C2371: “int8_t”: 重定义;不同的基类型 
8> c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): note: 参见“int8_t”的声明 
8>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
8> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
9>—— 已启动生成: 项目: frag_unittest, 配置: Debug Win32 —— 
7>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
7> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
7>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
7> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
7> 正在生成代码… 
9> frag_unittest.cc 
9>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
9> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
9>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
9> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
10>—— 已启动生成: 项目: malloc_hook_test, 配置: Debug Win32 —— 
11>—— 已启动生成: 项目: malloc_extension_test, 配置: Debug Win32 —— 
10> testutil.cc 
11> malloc_extension_test.cc 
6> nm-pdb.vcxproj -> D:/os.package/cpp/gperftools/gperftools-2.4/Debug/nm-pdb.exe 
12>—— 已启动生成: 项目: markidle_unittest, 配置: Debug Win32 —— 
5> addr2line-pdb.vcxproj -> D:/os.package/cpp/gperftools/gperftools-2.4/Debug/addr2line-pdb.exe 
13>—— 已启动生成: 项目: current_allocated_bytes_test, 配置: Debug Win32 —— 
12> testutil.cc 
10>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
11>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
10> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
11> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
10> malloc_hook_test.cc 
11>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
11> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
12>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
12> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
12> markidle_unittest.cc 
10>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
10> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
13> current_allocated_bytes_test.cc 
10>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
14>—— 已启动生成: 项目: packed-cache_test, 配置: Debug Win32 —— 
10> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
13>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
13> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
13>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
13> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
12>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
12> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
14> packed-cache_test.cc 
12>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
12> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
10>c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/time.h(39): error C2011: “timespec”:“struct”类型重定义 
10> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(440): note: 参见“timespec”的声明 
10> 正在生成代码… 
15>—— 已启动生成: 项目: pagemap_unittest, 配置: Debug Win32 —— 
14>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
14> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
14>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
14> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
14>d:/os.package/cpp/gperftools/gperftools-2.4/src/packed-cache-inl.h(224): warning C4293: “<<”: Shift 计数为负或过大,其行为未定义 
14> d:/os.package/cpp/gperftools/gperftools-2.4/src/tests/packed-cache_test.cc(38): note: 参见对正在编译的类 模板 实例化“PackedCache<64,uint64>”的引用 
16>—— 已启动生成: 项目: page_heap_test, 配置: Debug Win32 —— 
17>—— 已启动生成: 项目: realloc_unittest, 配置: Debug Win32 —— 
17> realloc_unittest.cc 
16> page_heap_test.cc 
12> 正在生成代码… 
15> pagemap_unittest.cc 
15>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
15> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
15>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
15> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
18>—— 已启动生成: 项目: sampler_test, 配置: Debug Win32 —— 
19>—— 已启动生成: 项目: stack_trace_table_test, 配置: Debug Win32 —— 
17>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
17> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
17>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
17> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
16>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
16> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
18> sampler_test.cc 
16>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
16> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
20>—— 已启动生成: 项目: thread_dealloc_unittest, 配置: Debug Win32 —— 
21>—— 已跳过生成: 项目: preamble_patcher_test, 配置: Debug Win32 —— 
21>没有为此解决方案配置选中要生成的项目 
22>—— 已启动生成: 项目: system-alloc_unittest, 配置: Debug Win32 —— 
18>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
18> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
18>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
18> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
20> thread_dealloc_unittest.cc 
20>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
20> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
20>c:/program files (x86)/microsoft visual studio 14.0/vc/include/stdint.h(17): error C2371: “int8_t”: 重定义;不同的基类型 
20> d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(104): note: 参见“int8_t”的声明 
20> testutil.cc 
20>d:/os.package/cpp/gperftools/gperftools-2.4/src/windows/port.h(328): error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
20> c:/program files (x86)/windows kits/10/include/10.0.10150.0/ucrt/stdio.h(1932): note: 参见“snprintf”的前一个定义 
20> 正在生成代码… 
========== 生成: 成功 2 个,失败 19 个,最新 0 个,跳过 1 个 ==========

修改config.h

看到上面的一大堆报错,脑子一下子就晕了,尼玛,什么玩意儿,编译器支持这么差?没有说明不支持vs编译器啊。 
仔细分析上面的错误信息,发现主要就是snprintfint8_ttimespec重定义,

error C2084: 函数“int snprintf(char *const ,const size_t,const char *const ,…)”已有主体 
error C2371: “int8_t”: 重定义;不同的基类型 
error C2011: “timespec”:“struct”类型重定义

考虑到vs2015比较新,用google搜索了一下”tcmalloc vs2010”,发现了这篇文章《TCMalloc static lib in vs2010》

文中解决的问题我并不关心,但我发现了这个:(#define WIN32_OVERRIDE_ALLOCATORS in config.h). 
打开gperftools的源文件夹,在/src/windows下面果然发现找到了文中提到的config.h以及提到的宏定义WIN32_OVERRIDE_ALLOCATORS 
这里写图片描述

这里写图片描述

我才明白,gpreftools为了能根据需要编译出不特性的代码,以及适应在不同版本的编译器下正常编译,设计了这个config.h通过宏定义来控制代码生成。在不同的编译器下编译,要根据编译报错的信息来相应修改config.h来解决。上图中最后一行,就是关于snprintf的

/* Define to 1 if your libc has a snprintf implementation */#undef HAVE_SNPRINTF
  • 1
  • 2
  • 1
  • 2

根据注释的说明,如果编译已经有snprintf 的实现,就要将HAVE_SNPRINTF定义为1

根据 www.cplusplus.com上关于snprintf的说明,snprintf是C++11支持的函数 
VS2015版本已经有了snprintf的实现,所以要修改config.hHAVE_SNPRINTF的定义

/* Define to 1 if your libc has a snprintf implementation */#define HAVE_SNPRINTF 1
  • 1
  • 2
  • 1
  • 2

同样的道理,关于int8_t,也是因为int8_t所在的文件<stdint.h>已经是C++11的标准头文件,参见<cstdint> (stdint.h)

config.h中找到下面的定义

/* Define to 1 if you have the <stdint.h> header file. */#undef HAVE_STDINT_H
  • 1
  • 2
  • 1
  • 2

改为

/* Define to 1 if you have the <stdint.h> header file. */#define HAVE_STDINT_H 1
  • 1
  • 2
  • 1
  • 2

至于timespec也是因为定义在port.h中的timespec与c++标准头文件time.h中的timespec定义重复

这是port.h中的关于timespec的代码片段,看代码注释,是因为mingw没有定义timespc,而且mingw64中有定义,所以有点混乱,所以在这里用_TIMESPEC_DEFINED来做一个保护

// mingw64 seems to define timespec (though mingw.org mingw doesn't),// protected by the _TIMESPEC_DEFINED macro.#ifndef _TIMESPEC_DEFINEDstruct timespec {  int tv_sec;  int tv_nsec;};#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

而在<time.h>是通过_CRT_NO_TIME_T来控制是否定义timespec

#ifndef _CRT_NO_TIME_T    struct timespec    {        time_t tv_sec;  // Seconds - >= 0        long   tv_nsec; // Nanoseconds - [0, 999999999]    };#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

所以在config.h中加入下面一行,以去掉time.h中的timespec定义

#define _CRT_NO_TIME_T 1
  • 1
  • 1

最后保存config.h再编译,就可以通过了。

但是,编译通过只是第一步,是否能真的正常使用,还有待后面工作进行验证。

结论

要正确编译tcmalloc,应该根据c++编译器类型和版本的不同,修改config.h以达到与编译工具最匹配的状态,config.h中还有很多选项没有仔细研究,需要进一步深入了解。

第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台