Jump to content

Memory Pool


SpiderPig
 Share

Go to solution Solved by SpiderPig,

Recommended Posts

I've created a memory pool for voxel nodes rather than call new and delete for every single octree cell.  Everything appears to work correctly I'm just a bit confused with what VS tells me about the memory used.  It doesn't go down when cells are deleted, I've also placed GetMemoryUsage() before and after the delete keywords to test if there is a difference but most of the time there is not - if there is it has gone up not down.  Not sure if it takes time to process the memory change or not?

Pages are definitely being deleted and created when they should be, memory goes up only when new pages are created after it uses the existing memory allocated in previous pages.  But the memory never goes down.  Release is the same.

I read that delete simply says to the OS that it can use that memory location for something else now and that technically your data could still be there if it hasn't been overridden.

Have I done anything stupidly wrong?

Header.h

struct VoxelPage {
	VoxelNode* nodes = nullptr;

	VoxelPage() {}
	~VoxelPage() { delete[] nodes; }
};

class VoxelPages {
private:
	uint64_t page_index = 0, page_total = 0;
	uint64_t voxel_index = 0;
	uint64_t size = 0, page_size = 0;
	VoxelPage** pages = nullptr;

public:
	VoxelPages(uint64_t size);
	~VoxelPages();

	void Reset();
	void Clean();
	void Destroy();
	VoxelNode* GetVoxelNode();
};

Source.cpp

VoxelPages::VoxelPages(uint64_t size) {
	this->size = size;
	page_size = size * size;
	pages = new VoxelPage*[size];
	for (int id = 0; id < size; id++) { pages[id] = nullptr; }

	pages[0] = new VoxelPage();
	pages[0]->nodes = new VoxelNode[page_size];
	page_total++;
}

VoxelPages::~VoxelPages() {
	Destroy();
}

void VoxelPages::Reset() {
	page_index = 0;
	voxel_index = 0;
}

void VoxelPages::Clean() {
	for (auto id = page_index + 1; id < page_total; id++) {
		delete pages[id];
		pages[id] = nullptr;
	}
	page_total = page_index + 1;
}

void VoxelPages::Destroy() {
	for (int id = 0; id < page_total; id++) {
		delete pages[id];
	}
	delete[] pages;
}

VoxelNode* VoxelPages::GetVoxelNode() {
	auto node = &pages[page_index]->nodes[voxel_index];

	voxel_index++;
	if (voxel_index == page_size) {
		voxel_index = 0;

		page_index++;
		if (page_index >= page_total) {
			pages[page_index] = new VoxelPage();
			pages[page_index]->nodes = new VoxelNode[page_size];
			page_total++;

			if (page_total == size) { Notify("VoxelPages::GetVoxelNode() : page_total exceeds size!", "Error", true); }
		}
	}

	return node;
}

 

Link to comment
Share on other sites

I usually use shared pointers so I don't even have to worry about leaks most of the time. You also need to consider that other threads that are running may be allocating memory.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I did start off using shared pointers but through a few simple tests found that raw pointers were faster.  I wrote a small console app to test it and it is working perfectly.

#include "Header.h"

int main()
{
    int component_size = 256;
    VoxelPages* pages = new VoxelPages(component_size);

    auto i = sizeof(VoxelNode);
    auto e = 128 * 128 * 128;
    for (int i = 0; i < e; i++) {
        auto my_node = pages->GetVoxelNode();
    }

    delete pages;

    while (true) {
    }
}

First off only the graph shows the current memory used, the number at the top right seems to be the max used so far.

MemoryUsage.png.c93df41897eddcebfbd8547861ea79b0.png

If this is working, that means I have a memory leak somewhere else.

Link to comment
Share on other sites

Not sure, but according to this description, auto variables are slower and constantly reserve and release memory than statically typed variables - even if both are resolved at compile time:
 

What is the difference between an auto and non auto variable?
 
 
Automatic variables create a new each time when program's execution enters in the function and destroys when leaves. Static variable create once, when program's execution enters in the function first time, destroys when program's execution finishes, they do not again.

I would always try to keep variable declarations before the iteration, just to be sure.

 

  • Like 1
  • Upvote 1

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

Do you mean the auto keyword?  I don't see how that would effect performance... but it's true, the my_node pointer in my example is going out of scope but the memory allocated in GetVoxelNode() remains untill I call : delete pages;  Declaring variables inside a loop should generally be avoided if possible for performace reasons.  But in this example speed of the allocation isn't a concern. 🙂

I can now see that the memory usage in VS diagnostic tools shows the maximum because that is the new range of the graph.

I wonder if you can get it to display the current memory usage without hovering the mouse over it...

Link to comment
Share on other sites

9 hours ago, SpiderPig said:

I did start off using shared pointers but through a few simple tests found that raw pointers were faster. 

They will be, slightly, because you don't have the extra overhead. There isn't anything wrong with raw pointers so long as there is a clear memory management pattern, but may not work well amongst larger teams of developers. With smart pointers you won't have leaks, and generally it is the accepted practise.

 

9 hours ago, Canardian said:

Not sure, but according to this description, auto variables are slower and constantly reserve and release memory than statically typed variables - even if both are resolved at compile time:
 

What is the difference between an auto and non auto variable?
 
 
Automatic variables create a new each time when program's execution enters in the function and destroys when leaves. Static variable create once, when program's execution enters in the function first time, destroys when program's execution finishes, they do not again.
 

This has been taken out of context (a link to quoted source is ideal). What you're referring to is the 'auto' keyword used in C, not C++. It is just comparing static variable declaration vs non-static. In C++, the type where auto keyword is used is automatically deduced by the compiler at compile time, and has no impact on performance.

Its true that static variables may be considered "faster" because your only initialzing them once, and destroying them once, but you'll often require logic to track their value. They have their purposes, but not overly common.

6 hours ago, SpiderPig said:

Declaring variables inside a loop should generally be avoided if possible for performace reasons. 

That's not necessarily true. You'll find that the compiler will optimize this and the difference will likely not be measurable or even existent.

  • Like 1
Link to comment
Share on other sites

3 hours ago, SpiderPig said:

On another memory related topic "world->renderstats.vram" is the VRAM available and not in use, correct?

Yeah, it’s the total VRAM. The Vulcan memory allocator has some commands for fetching mem usage but they are complicated and I haven’t looked into it much yet

  • Thanks 1

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...