Commit 420c2c3b authored by Nicola Castellani's avatar Nicola Castellani
Browse files

MM Done

parent 60488cf5
......@@ -5,9 +5,12 @@
#include "../Nica/Timer.h"
#include "../MemoryManager/Shared.h"
#include "DynamicAllocationObject.h"
#include "../MemoryManager/CustomSTLAllocator.h"
#include <iostream>
#include <string>
#include <cassert>
#include <list>
/**
* Here there are some tests to try custom allocators.
......@@ -18,45 +21,13 @@
typedef std::string String;
const String LOG_PRFX = "[Main] ";
#pragma endregion
/*
#pragma region Global Operators Overrides
void* operator new(std::size_t size) {
#ifdef USE_MM
return Nica::MemoryManager::get()->MM_NEW(size);
#else
return ::operator new(size);
#endif
}
void operator delete(void* p, std::size_t size) {
#ifdef USE_MM
Nica::MemoryManager::get()->MM_DELETE(p, size);
#else
::operator delete(p, size);
#endif
}
void* operator new[](std::size_t size) {
#ifdef USE_MM
return Nica::MemoryManager::get()->MM_NEW_A(size);
#else
return ::operator new(size);
#endif
}
void operator delete[](void* p, std::size_t size) {
#ifdef USE_MM
Nica::MemoryManager::get()->MM_DELETE_A(p, size);
#else
::operator delete(p, size);
#endif
}
#pragma endregion
*/
#pragma region TypeDefs
/**
* Complex numbers class, SmallObject
* @author nicola.castellani
*/
class Complex
class Complex : public Nica::DynamicAllocationObject
{
public:
Complex(double a, double b) : r(a), c(b) {}
......@@ -71,11 +42,24 @@ private:
class BigObjectExample : public Nica::DynamicAllocationObject
{
private:
double a, b, c, d, e, f, g, h, i;
double a, b, c, d, e, f, g, h, i; // 8b x 9 + 8b header
};
/**
* Custom non-fixed-size list with CustomSTLAllocator
* @author nicola.castellani
*/
template<class T, class A = Nica::CustomSTLAllocator<T>>
class nlist : public std::list<T, A>{};
#pragma endregion
#pragma region Tests
void Check(bool valid) {
Nica::PrintSpaceBetween({ "Test" }, { valid ? "Passed" : "Failed" }, valid ? BACKGROUND_GREEN : BACKGROUND_RED);
}
/**
* Instantiate Complex 10mln times and check if there are mem leaks
* @author nicola.castellani
......@@ -83,6 +67,7 @@ private:
void CheckComplexAllocation() {
Nica::PrintHR();
Complex* array[1000];
Nica::Timer::get()->start();
for (int i = 0; i < 5000; i++) {
......@@ -94,11 +79,10 @@ void CheckComplexAllocation() {
}
}
Nica::PrintSpaceBetween({ "Total execution time:" }, { std::to_string((float)Nica::Timer::get()->end() / 1000), "seconds" }, FOREGROUND_GREEN);
Nica::PrintSpaceBetween({ "Total execution time:" }, { std::to_string((float)Nica::Timer::get()->end() / 1000), "seconds" }, FOREGROUND_GREEN | FOREGROUND_RED);
Nica::MemoryManager::get()->Debug();
Nica::MemoryManager::get()->IsValid();
Nica::PrintSpaceBetween({ "Test" }, { "Passed" });
Check(Nica::MemoryManager::get()->IsValid());
Nica::MemoryManager::get()->Restart();
}
......@@ -117,8 +101,26 @@ void CreateMemoryLeak() {
void CheckMemoryLeak() {
CreateMemoryLeak();
Nica::MemoryManager::get()->Debug();
Nica::MemoryManager::get()->IsNotValid();
Nica::PrintSpaceBetween({ "Test" }, { "Passed" });
Check(Nica::MemoryManager::get()->IsNotValid());
Nica::MemoryManager::get()->Restart();
}
/**
* Creates dangling pointer for FL
* @author nicola.castellani
*/
void CreateFLMemoryLeak() {
BigObjectExample* ptr = new BigObjectExample();
return; // ptr is not deleted
}
/**
* Tests memory leaks handling with free list
* @author nicola.castellani
*/
void CheckFLMemoryLeak() {
CreateFLMemoryLeak();
Nica::MemoryManager::get()->Debug();
Check(Nica::MemoryManager::get()->IsNotValid());
Nica::MemoryManager::get()->Restart();
}
/**
......@@ -138,18 +140,77 @@ void CheckBigObjects() {
}
Nica::MemoryManager::get()->Debug();
Nica::MemoryManager::get()->IsValid();
Check(Nica::MemoryManager::get()->IsValid());
Nica::MemoryManager::get()->Restart();
}
void CreateNListAndDestroy() {
nlist<Complex*>* test = new nlist<Complex *>;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
test->push_back(new Complex(0, j));
}
for (int j = 0; j < 10; j++) {
// get current element
// delete element
delete test->front();
test->pop_front(); // this deletes and removes element
}
}
delete test;
}
void CreateNListWithLeak() {
nlist<Complex*>* test = new nlist<Complex*>;
test->push_back(new Complex(0, 0));
}
/**
* Tests instantiation with custom STL Allocator
* @author nicola.castellani
*/
void CheckSTLAllocator() {
CreateNListAndDestroy();
Nica::MemoryManager::get()->Debug();
Check(Nica::MemoryManager::get()->IsValid());
Nica::MemoryManager::get()->Restart();
}
/**
* Tests instantiation with custom STL Allocator, and memory leak check
* @author nicola.castellani
*/
void CheckSTLAllocatorLeak() {
CreateNListWithLeak();
Nica::PrintSpaceBetween({ "Test" }, { "Passed" });
Nica::MemoryManager::get()->Debug();
Check(Nica::MemoryManager::get()->IsNotValid());
Nica::MemoryManager::get()->Restart();
}
#pragma endregion
int main()
{
/* Small Object Allocator */
Nica::PrintTitle("TEST 1 >>> Check Complex class allocation", BACKGROUND_GREEN | BACKGROUND_RED);
CheckComplexAllocation();
Nica::PrintTitle("TEST 2 >>> Check Complex class allocation leak detection", BACKGROUND_GREEN | BACKGROUND_RED);
CheckMemoryLeak();
/* Free List Allocator */
Nica::PrintTitle("TEST 3 >>> Check big object class allocation", BACKGROUND_GREEN | BACKGROUND_RED);
CheckBigObjects();
Nica::PrintTitle("TEST 4 >>> Check big object class allocation leaks", BACKGROUND_GREEN | BACKGROUND_RED);
CheckFLMemoryLeak();
/* Custom STL Allocator */
Nica::PrintTitle("TEST 5 >>> Check custom STL allocation", BACKGROUND_GREEN | BACKGROUND_RED);
CheckSTLAllocator();
Nica::PrintTitle("TEST 6 >>> Check custom STL allocation leak detection", BACKGROUND_GREEN | BACKGROUND_RED);
CheckSTLAllocatorLeak();
return 0;
}
\ No newline at end of file
#include "pch.h"
#include "CustomSTLAllocator.h"
#pragma once
#include "MemoryManager.h"
#include "Shared.h"
#include <iostream>
#include <string>
namespace Nica {
template <typename T>
class CustomSTLAllocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
CustomSTLAllocator() {}
~CustomSTLAllocator() {}
template <class U> struct rebind { typedef CustomSTLAllocator<U> other; };
template <class U> CustomSTLAllocator(const CustomSTLAllocator<U>&) {}
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
size_type max_size() const throw() { return size_t(-1) / sizeof(value_type); }
pointer allocate(size_type n, const void* hint = 0)
{
#ifdef DEBUG_LOG
static int allocateCount;
Nica::PrintSpaceBetween(
{ "[CustomSTLAllocator]", "[ALLOCATE]" },
{ "# ", std::to_string(deleteCount), " [Pointer] ", std::to_string(p) }
);
allocateCount++;
#endif
return reinterpret_cast<pointer>(Nica::MemoryManager::get()->MM_NEW(n * sizeof(T)));
}
void deallocate(pointer p, size_type n)
{
#ifdef DEBUG_LOG
static int deleteCount;
Nica::PrintSpaceBetween(
{ "[CustomSTLAllocator]", "[DELETE]" },
{ "# ", std::to_string(deleteCount), " [Pointer] ", std::to_string(p) }
);
deleteCount++;
#endif
Nica::MemoryManager::get()->MM_DELETE(p, sizeof(T));
}
void construct(pointer p, const T& val)
{
new(static_cast<void*>(p)) T(val);
}
void construct(pointer p)
{
new(static_cast<void*>(p)) T();
}
void destroy(pointer p)
{
p->~T();
}
};
}
\ No newline at end of file
......@@ -109,7 +109,7 @@ void* Nica::FreeListAllocator::allocate(size_t size, u8 alignment)
#ifdef DEBUG_LOG
Nica::PrintSpaceBetween(
{ "[FreeListAllocator]", "Allocated new object:" },
{ "[FreeListAllocator]", "[ALLOCATE]" },
{ "Address: ", std::to_string(aligned_address), " Alignment: ", std::to_string(alignment) }
);
#endif
......@@ -127,7 +127,10 @@ void Nica::FreeListAllocator::deallocate(void* p)
size_t block_size = header->size;
uptr block_end = block_start + block_size;
#ifdef DEBUG_LOG
Nica::PrintSpaceBetween({ "[FreeListAllocator]" }, { "Deallocating size: ", std::to_string(block_size) });
Nica::PrintSpaceBetween(
{ "[FreeListAllocator]", "[DEALLOCATE]" },
{ "Address: ", std::to_string(block_start), " Of size: ", std::to_string(block_size) }
);
#endif
FreeBlock* prev_free_block = nullptr;
FreeBlock* free_block = _free_blocks;
......
// https://www.gamedev.net/articles/programming/general-and-gameplay-programming/c-custom-memory-allocation-r3010/
// https://github.com/tiagovcosta/aquaengine/blob/master/AquaEngine
#include "BaseAllocator.h"
namespace Nica {
/**
* Custom std::allocator using Free linked list
* @author nicola.castellani
*/
class FreeListAllocator : public BaseAllocator
{
public:
......@@ -13,6 +17,7 @@ namespace Nica {
void* allocate(size_t size, u8 alignment) override;
void deallocate(void* p) override;
private:
struct AllocationHeader { size_t size; u8 adjustment; };
......
......@@ -36,7 +36,7 @@ Nica::MemoryManager::~MemoryManager() {}
void* Nica::MemoryManager::MM_NEW(size_t t)
{
char isSmall = isSmallObject(t);
bool isSmall = isSmallObject(t);
if (isSmall) totMemAllocated_smallObject += t;
else totMemAllocated_bigObject += t;
return isSmall
......@@ -46,7 +46,7 @@ void* Nica::MemoryManager::MM_NEW(size_t t)
void* Nica::MemoryManager::MM_NEW_A(size_t t)
{
char isSmall = isSmallObject(t);
bool isSmall = isSmallObject(t);
if (isSmall) totMemAllocated_smallObject += t;
else totMemAllocated_bigObject += t;
return isSmall
......@@ -56,7 +56,9 @@ void* Nica::MemoryManager::MM_NEW_A(size_t t)
void Nica::MemoryManager::MM_DELETE(void* p, size_t t)
{
char isSmall = isSmallObject(t);
assert(p != nullptr);
bool isSmall = isSmallObject(t);
if (isSmall) totMemDeallocated_smallObject += t;
else totMemDeallocated_bigObject += t;
......@@ -67,7 +69,8 @@ void Nica::MemoryManager::MM_DELETE(void* p, size_t t)
void Nica::MemoryManager::MM_DELETE_A(void* p, size_t t)
{
char isSmall = isSmallObject(t);
assert(p != nullptr);
bool isSmall = isSmallObject(t);
if (isSmall) totMemDeallocated_smallObject += t;
else totMemDeallocated_bigObject += t;
......@@ -78,7 +81,7 @@ void Nica::MemoryManager::MM_DELETE_A(void* p, size_t t)
void* Nica::MemoryManager::MM_MALLOC(size_t t)
{
char isSmall = isSmallObject(t);
bool isSmall = isSmallObject(t);
if (isSmall) totMemAllocated_smallObject += t;
else totMemAllocated_bigObject += t;
......@@ -89,7 +92,8 @@ void* Nica::MemoryManager::MM_MALLOC(size_t t)
void Nica::MemoryManager::MM_FREE(void* p, size_t t)
{
char isSmall = isSmallObject(t);
assert(p != nullptr);
bool isSmall = isSmallObject(t);
if (isSmall) totMemDeallocated_smallObject += t;
else totMemDeallocated_bigObject += t;
......@@ -98,10 +102,9 @@ void Nica::MemoryManager::MM_FREE(void* p, size_t t)
: free(p);
}
bool Nica::MemoryManager::isSmallObject(size_t t)
char Nica::MemoryManager::isSmallObject(size_t t)
{
char isSmall = t <= MAX_SMALL_OBJECT_SIZE;
return isSmall;
return t <= MAX_SMALL_OBJECT_SIZE;
}
void Nica::MemoryManager::Debug()
......@@ -115,13 +118,13 @@ void Nica::MemoryManager::Debug()
Nica::PrintSpaceBetween({ "[SMALL]", "Total memory allocated: " }, { std::to_string(totMemAllocated_smallObject), "bytes" }, MM_CONSOLE_COLOR);
Nica::PrintSpaceBetween({ "[SMALL]", "Total memory deallocated: " }, { std::to_string(totMemDeallocated_smallObject), "bytes" }, MM_CONSOLE_COLOR);
Nica::PrintSpaceBetween({ "[BIG]", "Total memory allocated: " }, { std::to_string(totMemAllocated_bigObject), "bytes" }, MM_CONSOLE_COLOR);
Nica::PrintSpaceBetween({ "[BIG]", "Total memory deallocated: " }, { std::to_string(totMemDeallocated_bigObject), "bytes" }, MM_CONSOLE_COLOR);
Nica::PrintHR();
Nica::PrintSpaceBetween({ "[BIG] ", "Total memory allocated: " }, { std::to_string(totMemAllocated_bigObject), "bytes" }, MM_CONSOLE_COLOR);
Nica::PrintSpaceBetween({ "[BIG] ", "Total memory deallocated: " }, { std::to_string(totMemDeallocated_bigObject), "bytes" }, MM_CONSOLE_COLOR);
Nica::PrintNewLine();
if (totMemDeallocated_smallObject == totMemAllocated_smallObject) {
if (IsValid()) {
Nica::PrintSpaceBetween({ "Memory leaks: " }, { "NOT DETECTED" }, FOREGROUND_GREEN);
}
else {
......@@ -133,27 +136,18 @@ void Nica::MemoryManager::Debug()
void Nica::MemoryManager::Restart()
{
totMemAllocated_smallObject = totMemDeallocated_smallObject = 0;
}
void Nica::MemoryManager::IsValid()
{
assert(totMemAllocated_smallObject == totMemAllocated_smallObject);
}
void Nica::MemoryManager::IsNotValid()
{
assert(totMemAllocated_smallObject != totMemAllocated_smallObject);
totMemAllocated_smallObject = totMemDeallocated_smallObject = totMemDeallocated_bigObject = totMemAllocated_bigObject = 0;
}
void Nica::MemoryManager::allocated(size_t bytes)
char Nica::MemoryManager::IsValid()
{
totMemAllocated_smallObject += bytes;
char valid = totMemAllocated_smallObject == totMemDeallocated_smallObject && totMemDeallocated_bigObject == totMemAllocated_bigObject;
return valid;
}
void Nica::MemoryManager::deallocated(size_t bytes)
char Nica::MemoryManager::IsNotValid()
{
totMemDeallocated_smallObject += bytes;
return !IsValid();
}
Nica::MemoryManager* Nica::MemoryManager::get()
......
......@@ -33,17 +33,13 @@ namespace Nica {
virtual void MM_DELETE_A(void* p, size_t t);
virtual void MM_FREE(void* p, size_t t);
bool isSmallObject(size_t t);
char isSmallObject(size_t t);
void Debug();
void Restart();
void IsValid();
void IsNotValid();
public:
void allocated(size_t bytes);
void deallocated(size_t bytes);
char IsValid();
char IsNotValid();
public:
static MemoryManager* get();
......
......@@ -153,6 +153,7 @@
<ItemGroup>
<ClInclude Include="BaseAllocator.h" />
<ClInclude Include="Chunk.h" />
<ClInclude Include="CustomSTLAllocator.h" />
<ClInclude Include="FixedAllocator.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="FreeListAllocator.h" />
......
......@@ -63,6 +63,9 @@
<ClInclude Include="Mallocator.h">
<Filter>Header Files\CustomAllocation</Filter>
</ClInclude>
<ClInclude Include="CustomSTLAllocator.h">
<Filter>Header Files\CustomAllocation</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="MemoryManager.cpp">
......
......@@ -13,7 +13,7 @@ namespace { // anonymous
#define USE_MM
#endif
#ifndef DEBUG_LOG
/*#ifndef DEBUG_LOG
#define DEBUG_LOG
#endif
#endif*/
}
\ No newline at end of file
#include "pch.h"
#include "SmallObjectAllocator.h"
#include "FixedAllocator.h"
#include "../Nica/Print.h"
#include "Shared.h"
#include <functional>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
Nica::SmallObjectAllocator::SmallObjectAllocator()
:pLastAlloc_(0), pLastDealloc_(0)
......@@ -34,7 +35,16 @@ void* Nica::SmallObjectAllocator::allocate(std::size_t numBytes)
pLastDealloc_ = &*pool_.begin();
}
pLastAlloc_ = &*i;
return pLastAlloc_->allocate();
void* result = pLastAlloc_->allocate();
#ifdef DEBUG_LOG
Nica::PrintSpaceBetween(
{ "[SmallObjAllocator]", "[New allocation]" },
{ "[Pointer]", std::to_string(reinterpret_cast<uintptr_t>(result)), " [Size] ", std::to_string(numBytes)});
#endif
return result;
}
void Nica::SmallObjectAllocator::deallocate(void* p, std::size_t numBytes)
......
......@@ -8,7 +8,7 @@ const char SPECIAL_CHAR_TITLE = '=';
const char EMPTY_CHAR = ' ';
typedef unsigned int UINT;
const UINT ROW_LEN = 50;
const UINT ROW_LEN = 74;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
template<class U>
......@@ -92,7 +92,8 @@ void Nica::PrintTitle(String title, WORD consoleTextAttr, UINT padding)
result += (i > center + titleLen / 2 + padding) ? SPECIAL_CHAR_TITLE : ' ';
}
std::cout << result << '\n';
std::cout << result;
PrintNewLine();
SetConsoleAttribute();
PrintHR();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment