Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does everyone use 2^n numbers for allocation? -> new StringBuilder(256)

15 years ago, while programming with Pascal, I understood why to use power of two's for memory allocation. But this still seems to be state-of-the-art.

C# Examples:

new StringBuilder(256);
new byte[1024];
int bufferSize = 1 << 12;

I still see this thousands of times, I use this myself and I'm still questioning:

Do we need this in modern programming languages and modern hardware?
I guess its good practice, but what's the reason?

EDIT
For example a byte[] array, as stated by answers here, a power of 2 will make no sense: the array itself will use 16 bytes (?), so does it make sense to use 240 (=256-16) for the size to fit a total of 256 bytes?

like image 885
joe Avatar asked Aug 13 '13 06:08

joe


3 Answers

Do we need this in modern programming languages and modern hardware? I guess its good practice, but what's the reason?

It depends. There are two things to consider here:

  1. For sizes less than the memory page size, there's no appreciable difference between a power-of-two and an arbitrary number to allocate space;
  2. You mostly use managed data structures with C#, so you won't even know how many bytes are really allocated underneath.

Assuming you're doing low-level allocation with malloc(), using multiples of the page size would be considered a good idea, i.e. 4096 or 8192; this is because it allows for more efficient memory management.

My advice would be to just allocate what you need and let C# handle the memory management and allocation for you.

like image 145
Ja͢ck Avatar answered Oct 20 '22 01:10

Ja͢ck


It still makes sense in certain cases, but I would prefer to analyze case-by-case whether I need that kind of specification or not, rather than blindly use it as good practice.

For example, there might be cases where you want to use exactly 8 bits of information (1 byte) to address a table.

In that case, I would let the table have the size of 2^8.

Object table = new Object[256];

By this, you will be able to address any object of the table using only one byte.

Even if the table is actually smaller and doesn't use all 256 places, you still have the guarantee of bidirectional mapping from table to index and from index to table, which could prevent errors that would appear, for example, if you had:

Object table = new Object[100];

And then someone (probably someone else) accesses it with a byte value out of table's range.

Maybe this kind of bijective behavior could be good, maybe you could have other ways to guarantee your constraints.

Probably, given the increase in smartness of current compilers, it is not the only good practice anymore.

like image 22
Lake Avatar answered Oct 20 '22 00:10

Lake


Sadly, it's quite stupid if you want to keep a block of memory in a single memory page of 4k... And persons don't even know it :-) (I didn't until 10 minutes ago... I only had an hunch)... An example... It's unsafe code and implementation dependant (using .NET 4.5 at 32/64 bits)

byte[] arr = new byte[4096];

fixed (byte* p = arr)
{
    int size = ((int*)p)[IntPtr.Size == 4 ? -1 : -2];
}

So the CLR has allocated at least 4096 + (1 or 2) sizeof(int)... So it has gone over one 4k memory page. This is logical... It has to keep the size of the array somewhere, and keeping it together with the array is the most intelligent thing (for those that know what Pascal Strings and BSTR are, yes, it's the same principle)

I'll add that all the objects in .NET have a syncblck number and a RuntimeType... They are at least int if not IntPtr, so a total of between 8 and 16 bytes/object (This is explained in various places... try looking for .net object header if you are interested)

like image 27
xanatos Avatar answered Oct 20 '22 02:10

xanatos