chrome中tcmalloc的使用
chrome中内存分配采用了第三方库tcmalloc,这个库主要提供给应用程序内存管理方面的优化,按资料说内存存取速度会从300ns降到50ns。更具体的关于这个tcmalloc的信息大家可以查网上的资料看看, 本人对tcmalloc的实现不是很熟,这里主要向熟悉一下chrome的代码,主要说说 tcmalloc如何集成到了chrome中,通过研究这个,一是看看如何使用tcmalloc,另外可以对window下VC的内存C runtime的库有更多的了解。
tcmalloc主要提供了自有的一套内存分配的函数,来替换我们常使用的new delete等VC++默认提供的内存分配实现。
chrome中的tcmalloc的源码位于third_party下,源代码通过GYP引入到chrome中的allocator项目中,我们重点可以看下 allocator_shim.cc中的代码。该文件中对外提供了内存分配的malloc, free和reallocator等函数,用来接管系统默认提供的内存非配函数。
extern "C" { void* malloc(size_t size) __THROW { void* ptr; for (;;) { #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING switch (allocator) { case JEMALLOC: ptr = je_malloc(size); break; case WINHEAP: case WINLFH: ptr = win_heap_malloc(size); break; case TCMALLOC: default: ptr = do_malloc(size); break; } #else // TCMalloc case. ptr = do_malloc(size); #endif if (ptr) return ptr; if (!new_mode || !call_new_handler(true)) break; } return ptr; } void free(void* p) __THROW { #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING switch (allocator) { case JEMALLOC: je_free(p); return; case WINHEAP: case WINLFH: win_heap_free(p); return; } #endif // TCMalloc case. do_free(p); } void* realloc(void* ptr, size_t size) __THROW { // Webkit is brittle for allocators that return NULL for malloc(0). The // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure // to call malloc for this case. if (!ptr) return malloc(size); void* new_ptr; for (;;) { #ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING switch (allocator) { case JEMALLOC: new_ptr = je_realloc(ptr, size); break; case WINHEAP: case WINLFH: new_ptr = win_heap_realloc(ptr, size); break; case TCMALLOC: default: new_ptr = do_realloc(ptr, size); break; } #else // TCMalloc case. new_ptr = do_realloc(ptr, size); #endif // Subtle warning: NULL return does not alwas indicate out-of-memory. If // the requested new size is zero, realloc should free the ptr and return // NULL. if (new_ptr || !size) return new_ptr; if (!new_mode || !call_new_handler(true)) break; } return new_ptr; }
通过这三个函数的代码我们可以看出,chrome提供了进行内存库切换的枚举, 不同的枚举值对应不同的具体malloc的实现转发,具体由JEMalloc, tcmalloc和默认等几种不同的内存库可以使用。
按照我们的经验,如果直接编译的话,那么就会有两份的malloc的实现,此时链接是不会通过的,chrome中如何解决?
chrome下的base中allocator相关的项目有4个,其中有一个名为libcmt的项目,其中只有一个python的脚本, 代码如下:
#!/usr/bin/env python # Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # # This script takes libcmt.lib for VS2005/08/10/12/13 and removes the allocation # related functions from it. # # Usage: prep_libc.py <VCLibDir> <OutputDir> <arch> # # VCLibDir is the path where VC is installed, something like: # C:\Program Files\Microsoft Visual Studio 8\VC\lib # OutputDir is the directory where the modified libcmt file should be stored. # arch is either 'ia32' or 'x64' import os import shutil import subprocess import sys def run(command, filter=None): """Run |command|, removing any lines that match |filter|. The filter is to remove the echoing of input filename that 'lib' does.""" popen = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, _ = popen.communicate() for line in out.splitlines(): if filter and line.strip() != filter: print line return popen.returncode def main(): bindir = 'SELF_X86' objdir = 'INTEL' vs_install_dir = sys.argv[1] outdir = sys.argv[2] if "x64" in sys.argv[3]: bindir = 'SELF_64_amd64' objdir = 'amd64' vs_install_dir = os.path.join(vs_install_dir, 'amd64') output_lib = os.path.join(outdir, 'libcmt.lib') shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib) shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'), os.path.join(outdir, 'libcmt.pdb')) vspaths = [ 'build\\intel\\mt_obj\\', 'f:\\dd\\vctools\\crt_bld\\' + bindir + \ '\\crt\\src\\build\\' + objdir + '\\mt_obj\\', 'F:\\dd\\vctools\\crt_bld\\' + bindir + \ '\\crt\\src\\build\\' + objdir + '\\mt_obj\\nativec\\\\', 'F:\\dd\\vctools\\crt_bld\\' + bindir + \ '\\crt\\src\\build\\' + objdir + '\\mt_obj\\nativecpp\\\\', 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \ '\\crt\\prebuild\\build\\INTEL\\mt_obj\\cpp_obj\\\\', ] objfiles = ['malloc', 'free', 'realloc', 'new', 'delete', 'new2', 'delete2', 'align', 'msize', 'heapinit', 'expand', 'heapchk', 'heapwalk', 'heapmin', 'sbheap', 'calloc', 'recalloc', 'calloc_impl', 'new_mode', 'newopnt', 'newaopnt'] for obj in objfiles: for vspath in vspaths: cmd = ('lib /nologo /ignore:4006,4014,4221 /remove:%s%s.obj %s' % (vspath, obj, output_lib)) run(cmd, obj + '.obj') if __name__ == "__main__": sys.exit(main())
这段代码主要 是从libcmt.lib中移出 malloc, free, new 等 的obj的默认实现, 就可以使用到我们所提供的malloc了。