📄 fastmalloc.cpp
字号:
// Copyright (c) 2005, 2007, Google Inc.// All rights reserved.// Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.// // Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met:// // * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.// ---// Author: Sanjay Ghemawat <opensource@google.com>//// A malloc that uses a per-thread cache to satisfy small malloc requests.// (The time for malloc/free of a small object drops from 300 ns to 50 ns.)//// See doc/tcmalloc.html for a high-level// description of how this malloc works.//// SYNCHRONIZATION// 1. The thread-specific lists are accessed without acquiring any locks.// This is safe because each such list is only accessed by one thread.// 2. We have a lock per central free-list, and hold it while manipulating// the central free list for a particular size.// 3. The central page allocator is protected by "pageheap_lock".// 4. The pagemap (which maps from page-number to descriptor),// can be read without holding any locks, and written while holding// the "pageheap_lock".// 5. To improve performance, a subset of the information one can get// from the pagemap is cached in a data structure, pagemap_cache_,// that atomically reads and writes its entries. This cache can be// read and written without locking.//// This multi-threaded access to the pagemap is safe for fairly// subtle reasons. We basically assume that when an object X is// allocated by thread A and deallocated by thread B, there must// have been appropriate synchronization in the handoff of object// X from thread A to thread B. The same logic applies to pagemap_cache_.//// THE PAGEID-TO-SIZECLASS CACHE// Hot PageID-to-sizeclass mappings are held by pagemap_cache_. If this cache// returns 0 for a particular PageID then that means "no information," not that// the sizeclass is 0. The cache may have stale information for pages that do// not hold the beginning of any free()'able object. Staleness is eliminated// in Populate() for pages with sizeclass > 0 objects, and in do_malloc() and// do_memalign() for all other relevant pages.//// TODO: Bias reclamation to larger addresses// TODO: implement mallinfo/mallopt// TODO: Better testing//// 9/28/2003 (new page-level allocator replaces ptmalloc2):// * malloc/free of small objects goes from ~300 ns to ~50 ns.// * allocation of a reasonably complicated struct// goes from about 1100 ns to about 300 ns.#include "config.h"#include "FastMalloc.h"#include "Assertions.h"#if ENABLE(JSC_MULTIPLE_THREADS)#include <pthread.h>#endif#ifndef NO_TCMALLOC_SAMPLES#ifdef WTF_CHANGES#define NO_TCMALLOC_SAMPLES#endif#endif#if !defined(USE_SYSTEM_MALLOC) && defined(NDEBUG)#define FORCE_SYSTEM_MALLOC 0#else#define FORCE_SYSTEM_MALLOC 1#endif#define TCMALLOC_TRACK_DECOMMITED_SPANS (HAVE(VIRTUALALLOC))#ifndef NDEBUGnamespace WTF {#if ENABLE(JSC_MULTIPLE_THREADS)static pthread_key_t isForbiddenKey;static pthread_once_t isForbiddenKeyOnce = PTHREAD_ONCE_INIT;static void initializeIsForbiddenKey(){ pthread_key_create(&isForbiddenKey, 0);}static bool isForbidden(){ pthread_once(&isForbiddenKeyOnce, initializeIsForbiddenKey); return !!pthread_getspecific(isForbiddenKey);}void fastMallocForbid(){ pthread_once(&isForbiddenKeyOnce, initializeIsForbiddenKey); pthread_setspecific(isForbiddenKey, &isForbiddenKey);}void fastMallocAllow(){ pthread_once(&isForbiddenKeyOnce, initializeIsForbiddenKey); pthread_setspecific(isForbiddenKey, 0);}#elsestatic bool staticIsForbidden;static bool isForbidden(){ return staticIsForbidden;}void fastMallocForbid(){ staticIsForbidden = true;}void fastMallocAllow(){ staticIsForbidden = false;}#endif // ENABLE(JSC_MULTIPLE_THREADS)} // namespace WTF#endif // NDEBUG#include <string.h>namespace WTF {void* fastZeroedMalloc(size_t n) { void* result = fastMalloc(n); memset(result, 0, n); return result;} void* tryFastZeroedMalloc(size_t n) { void* result = tryFastMalloc(n); if (!result) return 0; memset(result, 0, n); return result;}} // namespace WTF#if FORCE_SYSTEM_MALLOC#include <stdlib.h>#if !PLATFORM(WIN_OS) #include <pthread.h>#else #include "windows.h"#endifnamespace WTF {void* tryFastMalloc(size_t n) { ASSERT(!isForbidden()); return malloc(n);}void* fastMalloc(size_t n) { ASSERT(!isForbidden()); void* result = malloc(n); if (!result) CRASH(); return result;}void* tryFastCalloc(size_t n_elements, size_t element_size){ ASSERT(!isForbidden()); return calloc(n_elements, element_size);}void* fastCalloc(size_t n_elements, size_t element_size){ ASSERT(!isForbidden()); void* result = calloc(n_elements, element_size); if (!result) CRASH(); return result;}void fastFree(void* p){ ASSERT(!isForbidden()); free(p);}void* tryFastRealloc(void* p, size_t n){ ASSERT(!isForbidden()); return realloc(p, n);}void* fastRealloc(void* p, size_t n){ ASSERT(!isForbidden()); void* result = realloc(p, n); if (!result) CRASH(); return result;}void releaseFastMallocFreeMemory() { } FastMallocStatistics fastMallocStatistics(){ FastMallocStatistics statistics = { 0, 0, 0, 0 }; return statistics;}} // namespace WTF#if PLATFORM(DARWIN)// This symbol is present in the JavaScriptCore exports file even when FastMalloc is disabled.// It will never be used in this case, so it's type and value are less interesting than its presence.extern "C" const int jscore_fastmalloc_introspection = 0;#endif#else // FORCE_SYSTEM_MALLOC#if HAVE(STDINT_H)#include <stdint.h>#elif HAVE(INTTYPES_H)#include <inttypes.h>#else#include <sys/types.h>#endif#include "AlwaysInline.h"#include "Assertions.h"#include "TCPackedCache.h"#include "TCPageMap.h"#include "TCSpinLock.h"#include "TCSystemAlloc.h"#include <algorithm>#include <errno.h>#include <new>#include <pthread.h>#include <stdarg.h>#include <stddef.h>#include <stdio.h>#if COMPILER(MSVC)#ifndef WIN32_LEAN_AND_MEAN#define WIN32_LEAN_AND_MEAN#endif#include <windows.h>#endif#if WTF_CHANGES#if PLATFORM(DARWIN)#include "MallocZoneSupport.h"#include <wtf/HashSet.h>#endif#ifndef PRIuS#define PRIuS "zu"#endif// Calling pthread_getspecific through a global function pointer is faster than a normal// call to the function on Mac OS X, and it's used in performance-critical code. So we// use a function pointer. But that's not necessarily faster on other platforms, and we had// problems with this technique on Windows, so we'll do this only on Mac OS X.#if PLATFORM(DARWIN)static void* (*pthread_getspecific_function_pointer)(pthread_key_t) = pthread_getspecific;#define pthread_getspecific(key) pthread_getspecific_function_pointer(key)#endif#define DEFINE_VARIABLE(type, name, value, meaning) \ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead { \ type FLAGS_##name(value); \ char FLAGS_no##name; \ } \ using FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead::FLAGS_##name #define DEFINE_int64(name, value, meaning) \ DEFINE_VARIABLE(int64_t, name, value, meaning) #define DEFINE_double(name, value, meaning) \ DEFINE_VARIABLE(double, name, value, meaning)namespace WTF {#define malloc fastMalloc#define calloc fastCalloc#define free fastFree#define realloc fastRealloc#define MESSAGE LOG_ERROR#define CHECK_CONDITION ASSERT#if PLATFORM(DARWIN)class Span;class TCMalloc_Central_FreeListPadded;class TCMalloc_PageHeap;class TCMalloc_ThreadCache;template <typename T> class PageHeapAllocator;class FastMallocZone {public: static void init(); static kern_return_t enumerate(task_t, void*, unsigned typeMmask, vm_address_t zoneAddress, memory_reader_t, vm_range_recorder_t); static size_t goodSize(malloc_zone_t*, size_t size) { return size; } static boolean_t check(malloc_zone_t*) { return true; } static void print(malloc_zone_t*, boolean_t) { } static void log(malloc_zone_t*, void*) { } static void forceLock(malloc_zone_t*) { } static void forceUnlock(malloc_zone_t*) { } static void statistics(malloc_zone_t*, malloc_statistics_t* stats) { memset(stats, 0, sizeof(malloc_statistics_t)); }private: FastMallocZone(TCMalloc_PageHeap*, TCMalloc_ThreadCache**, TCMalloc_Central_FreeListPadded*, PageHeapAllocator<Span>*, PageHeapAllocator<TCMalloc_ThreadCache>*); static size_t size(malloc_zone_t*, const void*); static void* zoneMalloc(malloc_zone_t*, size_t); static void* zoneCalloc(malloc_zone_t*, size_t numItems, size_t size); static void zoneFree(malloc_zone_t*, void*); static void* zoneRealloc(malloc_zone_t*, void*, size_t); static void* zoneValloc(malloc_zone_t*, size_t) { LOG_ERROR("valloc is not supported"); return 0; } static void zoneDestroy(malloc_zone_t*) { } malloc_zone_t m_zone; TCMalloc_PageHeap* m_pageHeap; TCMalloc_ThreadCache** m_threadHeaps; TCMalloc_Central_FreeListPadded* m_centralCaches; PageHeapAllocator<Span>* m_spanAllocator; PageHeapAllocator<TCMalloc_ThreadCache>* m_pageHeapAllocator;};#endif#endif#ifndef WTF_CHANGES// This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if// you're porting to a system where you really can't get a stacktrace.#ifdef NO_TCMALLOC_SAMPLES// We use #define so code compiles even if you #include stacktrace.h somehow.# define GetStackTrace(stack, depth, skip) (0)#else# include <google/stacktrace.h>#endif#endif// Even if we have support for thread-local storage in the compiler// and linker, the OS may not support it. We need to check that at// runtime. Right now, we have to keep a manual set of "bad" OSes.#if defined(HAVE_TLS) static bool kernel_supports_tls = false; // be conservative static inline bool KernelSupportsTLS() { return kernel_supports_tls; }# if !HAVE_DECL_UNAME // if too old for uname, probably too old for TLS static void CheckIfKernelSupportsTLS() { kernel_supports_tls = false; }# else# include <sys/utsname.h> // DECL_UNAME checked for <sys/utsname.h> too static void CheckIfKernelSupportsTLS() { struct utsname buf; if (uname(&buf) != 0) { // should be impossible MESSAGE("uname failed assuming no TLS support (errno=%d)\n", errno); kernel_supports_tls = false; } else if (strcasecmp(buf.sysname, "linux") == 0) { // The linux case: the first kernel to support TLS was 2.6.0 if (buf.release[0] < '2' && buf.release[1] == '.') // 0.x or 1.x kernel_supports_tls = false; else if (buf.release[0] == '2' && buf.release[1] == '.' && buf.release[2] >= '0' && buf.release[2] < '6' && buf.release[3] == '.') // 2.0 - 2.5 kernel_supports_tls = false; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -