1 | /* |
2 | * Copyright 2016-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | // http://www.canonware.com/download/jemalloc/jemalloc-latest/doc/jemalloc.html |
18 | |
19 | #pragma once |
20 | |
21 | #include <folly/CPortability.h> |
22 | #include <folly/portability/Config.h> |
23 | |
24 | #if defined(FOLLY_USE_JEMALLOC) && !FOLLY_SANITIZE |
25 | |
26 | #include <folly/portability/SysMman.h> |
27 | #include <jemalloc/jemalloc.h> |
28 | |
29 | #if (JEMALLOC_VERSION_MAJOR > 3) && defined(MADV_DONTDUMP) |
30 | #define FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED 1 |
31 | #if (JEMALLOC_VERSION_MAJOR == 4) |
32 | #define FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK |
33 | #define JEMALLOC_CHUNK_OR_EXTENT chunk |
34 | #else |
35 | #define FOLLY_JEMALLOC_NODUMP_ALLOCATOR_EXTENT |
36 | #define JEMALLOC_CHUNK_OR_EXTENT extent |
37 | #endif |
38 | #endif |
39 | |
40 | #endif // FOLLY_USE_JEMALLOC |
41 | |
42 | #include <cstddef> |
43 | |
44 | namespace folly { |
45 | |
46 | /** |
47 | * An allocator which uses Jemalloc to create an dedicated arena to allocate |
48 | * memory from. The only special property set on the allocated memory is that |
49 | * the memory is not dump-able. |
50 | * |
51 | * This is done by setting MADV_DONTDUMP using the `madvise` system call. A |
52 | * custom hook installed which is called when allocating a new chunk / extent of |
53 | * memory. All it does is call the original jemalloc hook to allocate the |
54 | * memory and then set the advise on it before returning the pointer to the |
55 | * allocated memory. Jemalloc does not use allocated chunks / extents across |
56 | * different arenas, without `munmap`-ing them first, and the advises are not |
57 | * sticky i.e. they are unset if `munmap` is done. Also this arena can't be used |
58 | * by any other part of the code by just calling `malloc`. |
59 | * |
60 | * If target system doesn't support MADV_DONTDUMP or jemalloc doesn't support |
61 | * custom arena hook, JemallocNodumpAllocator would fall back to using malloc / |
62 | * free. Such behavior can be identified by using |
63 | * !defined(FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED). |
64 | * |
65 | * Similarly, if binary isn't linked with jemalloc, the logic would fall back to |
66 | * malloc / free. |
67 | */ |
68 | class JemallocNodumpAllocator { |
69 | public: |
70 | enum class State { |
71 | ENABLED, |
72 | DISABLED, |
73 | }; |
74 | |
75 | // To be used as IOBuf::FreeFunction, userData should be set to |
76 | // reinterpret_cast<void*>(getFlags()). |
77 | static void deallocate(void* p, void* userData); |
78 | |
79 | explicit JemallocNodumpAllocator(State state = State::ENABLED); |
80 | |
81 | void* allocate(size_t size); |
82 | void* reallocate(void* p, size_t size); |
83 | void deallocate(void* p, size_t = 0); |
84 | |
85 | unsigned getArenaIndex() const { |
86 | return arena_index_; |
87 | } |
88 | int getFlags() const { |
89 | return flags_; |
90 | } |
91 | |
92 | private: |
93 | #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED |
94 | #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK |
95 | static chunk_alloc_t* original_alloc_; |
96 | static void* alloc( |
97 | void* chunk, |
98 | #else |
99 | static extent_hooks_t extent_hooks_; |
100 | static extent_alloc_t* original_alloc_; |
101 | static void* alloc( |
102 | extent_hooks_t* extent, |
103 | void* new_addr, |
104 | #endif |
105 | size_t size, |
106 | size_t alignment, |
107 | bool* zero, |
108 | bool* commit, |
109 | unsigned arena_ind); |
110 | #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED |
111 | |
112 | bool extend_and_setup_arena(); |
113 | |
114 | unsigned arena_index_{0}; |
115 | int flags_{0}; |
116 | }; |
117 | |
118 | /** |
119 | * JemallocNodumpAllocator singleton. |
120 | */ |
121 | JemallocNodumpAllocator& globalJemallocNodumpAllocator(); |
122 | |
123 | } // namespace folly |
124 | |