Blender V4.3
guarded_allocator.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#ifndef __UTIL_GUARDED_ALLOCATOR_H__
6#define __UTIL_GUARDED_ALLOCATOR_H__
7
8#include <cstddef>
9#include <cstdlib>
10#include <memory>
11
12#ifdef WITH_BLENDER_GUARDEDALLOC
14#endif
15
17
18/* Internal use only. */
19void util_guarded_mem_alloc(size_t n);
20void util_guarded_mem_free(size_t n);
21
22/* Guarded allocator for the use with STL. */
23template<typename T> class GuardedAllocator {
24 public:
25 typedef size_t size_type;
26 typedef ptrdiff_t difference_type;
27 typedef T *pointer;
28 typedef const T *const_pointer;
29 typedef T &reference;
30 typedef const T &const_reference;
31 typedef T value_type;
32
35
36 T *allocate(size_t n, const void *hint = 0)
37 {
38 (void)hint;
39 size_t size = n * sizeof(T);
41 if (n == 0) {
42 return NULL;
43 }
44 T *mem;
45#ifdef WITH_BLENDER_GUARDEDALLOC
46 /* C++ standard requires allocation functions to allocate memory suitably
47 * aligned for any standard type. This is 16 bytes for 64 bit platform as
48 * far as i concerned. We might over-align on 32bit here, but that should
49 * be all safe actually.
50 */
51 mem = (T *)MEM_mallocN_aligned(size, 16, "Cycles Alloc");
52#else
53 mem = (T *)malloc(size);
54#endif
55 if (mem == NULL) {
56 throw std::bad_alloc();
57 }
58 return mem;
59 }
60
61 void deallocate(T *p, size_t n)
62 {
63 util_guarded_mem_free(n * sizeof(T));
64 if (p != NULL) {
65#ifdef WITH_BLENDER_GUARDEDALLOC
66 MEM_freeN(p);
67#else
68 free(p);
69#endif
70 }
71 }
72
73 T *address(T &x) const
74 {
75 return &x;
76 }
77
78 const T *address(const T &x) const
79 {
80 return &x;
81 }
82
84 {
85 return *this;
86 }
87
88 size_t max_size() const
89 {
90 return size_t(-1);
91 }
92
93 template<class U> struct rebind {
95 };
96
97 template<class U> GuardedAllocator(const GuardedAllocator<U> &) {}
98
100 {
101 return *this;
102 }
103
104 inline bool operator==(GuardedAllocator const & /*other*/) const
105 {
106 return true;
107 }
108 inline bool operator!=(GuardedAllocator const &other) const
109 {
110 return !operator==(other);
111 }
112
113#ifdef _MSC_VER
114 /* Welcome to the black magic here.
115 *
116 * The issue is that MSVC C++ allocates container proxy on any
117 * vector initialization, including static vectors which don't
118 * have any data yet. This leads to several issues:
119 *
120 * - Static objects initialization fiasco (global_stats from
121 * util_stats.h might not be initialized yet).
122 * - If main() function changes allocator type (for example,
123 * this might happen with `blender --debug-memory`) nobody
124 * will know how to convert already allocated memory to a new
125 * guarded allocator.
126 *
127 * Here we work this around by making it so container proxy does
128 * not use guarded allocation. A bit fragile, unfortunately.
129 */
130 template<> struct rebind<std::_Container_proxy> {
131 typedef std::allocator<std::_Container_proxy> other;
132 };
133
134 operator std::allocator<std::_Container_proxy>() const
135 {
136 return std::allocator<std::_Container_proxy>();
137 }
138#endif
139};
140
141/* Get memory usage and peak from the guarded STL allocator. */
144
145/* Call given function and keep track if it runs out of memory.
146 *
147 * If it does run out f memory, stop execution and set progress
148 * to do a global cancel.
149 *
150 * It's not fully robust, but good enough to catch obvious issues
151 * when running out of memory.
152 */
153#define MEM_GUARDED_CALL(progress, func, ...) \
154 do { \
155 try { \
156 (func)(__VA_ARGS__); \
157 } \
158 catch (std::bad_alloc &) { \
159 fprintf(stderr, "Error: run out of memory!\n"); \
160 fflush(stderr); \
161 (progress)->set_error("Out of memory"); \
162 } \
163 } while (false)
164
166
167#endif /* __UTIL_GUARDED_ALLOCATOR_H__ */
void BLI_kdtree_nd_ free(KDTree *tree)
Read Guarded memory(de)allocation.
GuardedAllocator< T > & operator=(const GuardedAllocator &)
GuardedAllocator(const GuardedAllocator &)
bool operator==(GuardedAllocator const &) const
T * allocate(size_t n, const void *hint=0)
GuardedAllocator & operator=(const GuardedAllocator< U > &)
bool operator!=(GuardedAllocator const &other) const
T * address(T &x) const
GuardedAllocator(const GuardedAllocator< U > &)
const T * address(const T &x) const
void deallocate(T *p, size_t n)
size_t max_size() const
#define CCL_NAMESPACE_END
#define NULL
size_t util_guarded_get_mem_used()
size_t util_guarded_get_mem_peak()
void util_guarded_mem_free(size_t n)
CCL_NAMESPACE_BEGIN void util_guarded_mem_alloc(size_t n)
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:110
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define T
GuardedAllocator< U > other