1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "nel/misc/object_arena_allocator.h"
22 #include "nel/misc/fixed_size_allocator.h"
32 CObjectArenaAllocator
*CObjectArenaAllocator::_DefaultAllocator
= NULL
;
35 // *****************************************************************************************************************
36 CObjectArenaAllocator::CObjectArenaAllocator(uint maxAllocSize
, uint granularity
/* = 4*/)
38 nlassert(granularity
> 0);
39 nlassert(maxAllocSize
> 0);
40 _MaxAllocSize
= granularity
* ((maxAllocSize
+ (granularity
- 1)) / granularity
);
41 _ObjectSizeToAllocator
.resize(_MaxAllocSize
/ granularity
, NULL
);
42 _Granularity
= granularity
;
45 _WantBreakOnAlloc
= false;
50 // *****************************************************************************************************************
51 CObjectArenaAllocator::~CObjectArenaAllocator()
53 for(uint k
= 0; k
< _ObjectSizeToAllocator
.size(); ++k
)
55 delete _ObjectSizeToAllocator
[k
];
59 // *****************************************************************************************************************
60 void *CObjectArenaAllocator::alloc(uint size
)
63 if (_WantBreakOnAlloc
)
65 if (_AllocID
== _BreakAllocID
)
71 if (size
>= _MaxAllocSize
)
73 // use standard allocator
74 nlctassert(NL_DEFAULT_MEMORY_ALIGNMENT
>= sizeof(uint
));
75 uint8
*block
= (uint8
*)aligned_malloc(NL_DEFAULT_MEMORY_ALIGNMENT
+ (ptrdiff_t)size
, NL_DEFAULT_MEMORY_ALIGNMENT
); //new uint8[size + sizeof(uint)]; // an additionnal uint is needed to store size of block
76 if (!block
) throw std::bad_alloc();
78 _MemBlockToAllocID
[block
] = _AllocID
;
81 *(uint
*) block
= size
;
82 return block
+ NL_DEFAULT_MEMORY_ALIGNMENT
;
84 uint entry
= ((size
+ (_Granularity
- 1)) / _Granularity
) ;
85 nlassert(entry
< _ObjectSizeToAllocator
.size());
86 if (!_ObjectSizeToAllocator
[entry
])
88 _ObjectSizeToAllocator
[entry
] = new CFixedSizeAllocator(entry
* _Granularity
+ NL_DEFAULT_MEMORY_ALIGNMENT
, _MaxAllocSize
/ size
); // an additionnal uint is needed to store size of block
90 void *block
= _ObjectSizeToAllocator
[entry
]->alloc();
91 if (!block
) throw std::bad_alloc();
92 nlassert(((uintptr_t)block
% NL_DEFAULT_MEMORY_ALIGNMENT
) == 0);
94 _MemBlockToAllocID
[block
] = _AllocID
;
97 *(uint
*)block
= size
;
98 return (void *)((uint8
*)block
+ NL_DEFAULT_MEMORY_ALIGNMENT
);
101 // *****************************************************************************************************************
102 void CObjectArenaAllocator::freeBlock(void *block
)
105 uint8
*realBlock
= (uint8
*) block
- NL_DEFAULT_MEMORY_ALIGNMENT
; // sizeof(uint); // a uint is used at start of block to give its size
106 uint size
= *(uint
*) realBlock
;
107 if (size
>= _MaxAllocSize
)
110 std::map
<void *, uint
>::iterator it
= _MemBlockToAllocID
.find(realBlock
);
111 nlassert(it
!= _MemBlockToAllocID
.end());
112 _MemBlockToAllocID
.erase(it
);
114 aligned_free(realBlock
);
117 uint entry
= ((size
+ (_Granularity
- 1)) / _Granularity
);
118 nlassert(entry
< _ObjectSizeToAllocator
.size());
119 _ObjectSizeToAllocator
[entry
]->freeBlock(realBlock
);
121 std::map
<void *, uint
>::iterator it
= _MemBlockToAllocID
.find(realBlock
);
122 nlassert(it
!= _MemBlockToAllocID
.end());
125 if (_WantBreakOnAlloc)
127 if (it->second == _BreakAllocID)
134 _MemBlockToAllocID
.erase(it
);
138 // *****************************************************************************************************************
139 uint
CObjectArenaAllocator::getNumAllocatedBlocks() const
142 for(uint k
= 0; k
< _ObjectSizeToAllocator
.size(); ++k
)
144 if (_ObjectSizeToAllocator
[k
]) numObjs
+= _ObjectSizeToAllocator
[k
]->getNumAllocatedBlocks();
149 // *****************************************************************************************************************
150 CObjectArenaAllocator
&CObjectArenaAllocator::getDefaultAllocator()
152 if (!_DefaultAllocator
)
154 _DefaultAllocator
= new CObjectArenaAllocator(32768);
156 return *_DefaultAllocator
;
162 // *****************************************************************************************************************
163 void CObjectArenaAllocator::dumpUnreleasedBlocks()
165 for(std::map
<void *, uint
>::iterator it
= _MemBlockToAllocID
.begin(); it
!= _MemBlockToAllocID
.end(); ++it
)
167 nlinfo("block %u at adress %p remains", it
->second
, (static_cast<uint8
*>(it
->first
) + sizeof(uint
)));
171 // *****************************************************************************************************************
172 void CObjectArenaAllocator::setBreakForAllocID(bool enabled
, uint id
)
174 _WantBreakOnAlloc
= enabled
;