How Does a C++ Reference Look, Memory-Wise

How does a C++ reference look, memory-wise?

everywhere the reference j is encountered, it is replaced with the address of i. So basically the reference content address is resolved at compile time, and there is not need to dereference it like a pointer at run time.

Just to clarify what I mean by the address of i :

void function(int& x)
{
x = 10;
}

int main()
{
int i = 5;
int& j = i;

function(j);
}

In the above code, j should not take space on the main stack, but the reference x of function will take a place on its stack. That means when calling function with j as an argument, the address of i that will be pushed on the stack of function. The compiler can and should not reserve space on the main stack for j.

For the array part the standards say ::

C++ Standard 8.3.2/4:

There shall be no references to references, no arrays of references,
and no pointers to references.

Why arrays of references are illegal?

Tool to clearly visualize Memory Layout of a C Program

There are few methods to track memory allocation but none of them is a builtin method and all of them require some additional work on your side. In order to visualise memory you will have to use code instrumentation and/or event logging i.e. memory allocation and deallocation events and then replay all the events and generate graphs out of it.

Take a look at this paper:Visualizing Dynamic Memory Allocations (in C programs).

The GCSpy (for heap visualisation) is available here: https://www.cs.kent.ac.uk/projects/gc/gcspy/. While initially used for JVM, you can visualise the heap of a C program using for instance dlmalloc.

I completely understand why you would like to do that - I was looking for the same thing. While I don't find memory layout snapshotting very useful per se, I find observing how memory is being allocated over time very interesting and useful for debugging performance issues.

I remember that XCode had some instrumentation tools built in - never used them though, but perhaps worth exploring what they are offering.

What happens to memory after '\0' in a C string?

If I stick a '\0' into the middle of the allocated memory, does

(a.) free() still work properly, and

Yes.

(b.) does the space after the '\0' become inconsequential? Once '\0' is added, does the memory just get returned, or is it sitting there hogging space until free() is called?

Depends. Often, when you allocate large amounts of heap space, the system first allocates virtual address space - as you write to the pages some actual physical memory is assigned to back it (and that may later get swapped out to disk when your OS has virtual memory support). Famously, this distinction between wasteful allocation of virtual address space and actual physical/swap memory allows sparse arrays to be reasonably memory efficient on such OSs.

Now, the granularity of this virtual addressing and paging is in memory page sizes - that might be 4k, 8k, 16k...? Most OSs have a function you can call to find out the page size. So, if you're doing a lot of small allocations then rounding up to page sizes is wasteful, and if you have a limited address space relative to the amount of memory you really need to use then depending on virtual addressing in the way described above won't scale (for example, 4GB RAM with 32-bit addressing). On the other hand, if you have a 64-bit process running with say 32GB of RAM, and are doing relatively few such string allocations, you have an enormous amount of virtual address space to play with and the rounding up to page size won't amount to much.

But - note the difference between writing throughout the buffer then terminating it at some earlier point (in which case the once-written-to memory will have backing memory and could end up in swap) versus having a big buffer in which you only ever write to the first bit then terminate (in which case backing memory is only allocated for the used space rounded up to page size).

It's also worth pointing out that on many operating systems heap memory may not be returned to the Operating System until the process terminates: instead, the malloc/free library notifies the OS when it needs to grow the heap (e.g. using sbrk() on UNIX or VirtualAlloc() on Windows). In that sense, free() memory is free for your process to re-use, but not free for other processes to use. Some Operating Systems do optimise this - for example, using a distinct and independently releasble memory region for very large allocations.

Is it generally bad programming style to leave this hanging space there, in order to save some upfront programming time computing the necessary space before calling malloc?

Again, it depends on how many such allocations you're dealing with. If there are a great many relative to your virtual address space / RAM - you want to explicitly let the memory library know not all the originally requested memory is actually needed using realloc(), or you could even use strdup() to allocate a new block more tightly based on actual needs (then free() the original) - depending on your malloc/free library implementation that might work out better or worse, but very few applications would be significantly affected by any difference.

Sometimes your code may be in a library where you can't guess how many string instances the calling application will be managing - in such cases it's better to provide slower behaviour that never gets too bad... so lean towards shrinking the memory blocks to fit the string data (a set number of additional operations so doesn't affect big-O efficiency) rather than having an unknown proportion of the original string buffer wasted (in a pathological case - zero or one character used after arbitrarily large allocations). As a performance optimisation you might only bother returning memory if unusued space is >= the used space - tune to taste, or make it caller-configurable.

You comment on another answer:

So it comes down to judging whether the realloc will take longer, or the preprocessing size determination?

If performance is your top priority, then yes - you'd want to profile. If you're not CPU bound, then as a general rule take the "preprocessing" hit and do a right-sized allocation - there's just less fragmentation and mess. Countering that, if you have to write a special preprocessing mode for some function - that's an extra "surface" for errors and code to maintain. (This trade-off decision is commonly needed when implementing your own asprintf() from snprintf(), but there at least you can trust snprintf() to act as documented and don't personally have to maintain it).

Bytewise reading of memory: signed char * vs unsigned char *

You should use unsigned char. The C99 standard says that unsigned char is the only type guaranteed to be dense (no padding bits), and also defines that you may copy any object (except bitfields) exactly by copying it into an unsigned char array, which is the object representation in bytes.

The sensible interepretation of this is to me, that if you use a pointer to access an object as bytes, you should use unsigned char.

Reference: http://blackshell.com/~msmud/cstd.html#6.2.6.1 (From C1x draft C99)

Can the JVM GC move objects in the middle of a reference comparison, causing a comparison to fail even when both sides refer to the same object?

Java Bytecode instructions are always atomic in relation to the GC (i.e. no cycle can happen while a single instruction is being executed).

The only time the GC will run is between two Bytecode instructions.

Looking at the bytecode that javac generates for the if instruction in your code we can simply check to see if a GC would have any effect:

// a GC here wouldn't change anything
ALOAD 1
// a GC cycle here would update all references accordingly, even the one on the stack
ALOAD 2
// same here. A GC cycle will update all references to the object on the stack
IF_ACMPNE L3
// this is the comparison of the two references. no cycle can happen while this comparison
// "is running" so there won't be any problems with this either

Aditionally, even if the GC were able to run during the execution of a bytecode instruction, the references of the object would not change. It's still the same object before and after the cycle.

So, in short the answer to your question is no, it will always output true.

Data manipulation inside a function in C

This declaration of the parameter

void function2( float ¶m) {

is incorrect. In C there is no reference. Such a function declaration will be valid in C++, where references exist.

In C++ when the function is called like

function2(variable);

neither copy of the variable is created. The function refers to the original variable declared in main.

Is making smaller functions generally more efficient memory-wise since variables get deallocated more frequently?

It might reduce "high water mark" of stack usage for your program, and if so that might reduce the overall memory requirement of the program.

Yes, it depends on optimization. If the optimizer inlines the function calls, you might well find that all the variables of all the functions inlined are wrapped into one big stack frame. Any compiler worth using is capable of inlining[*], so the fact that it can happen doesn't depend on compiler. Exactly when it happens, will differ.

If your local variables are small, though, then it's fairly rare for your program to use more stack than has been automatically allocated to you at startup. Unless you go past what you're given initially, how much you use makes no difference to overall memory requirements.

If you're putting great big structures on the stack (multiple kilobytes), or if you're on a machine where a kilobyte is a lot of memory, then it might make a difference to overall memory usage. So, if by "a lot of local variables" you mean few dozen ints and pointers then no, nothing you do makes any significant difference. If by "a lot of local variables" you mean a few dozen 10k buffers, or if your function recurses very deep so that you have hundreds of levels of your few dozen ints, then it's a least possible it could make a difference, depending on the OS and configuration.

The model that stack and heap grow towards each other through general RAM, and the free memory in the middle can be used equally by either one of them, is obsolete. With the exception of a very few, very restricted systems, memory models are not designed that way any more. In modern OSes, we have so-called "virtual memory", and stack space is allocated to your program one page at a time. Most of them automatically allocate more pages of stack as it is used, up to a configured limit that's usually very large. A few don't automatically extend stack (Symbian last I used it, which was some years ago, didn't, although arguably Symbian is not a "modern" OS). If you're using an embedded OS, check what the manual says about stack.

Either way, the only thing that affects total memory use is how many pages of stack you need at any one time. If your system automatically extends stack, you won't even notice how much you're using. If it doesn't, you'll need to ensure that the program is given sufficient stack for its high-water mark, and that's when you might notice excessive stack use.

In short, this is one of those things that in theory makes a difference, but in practice that difference is almost always insignificant. It only matters if your program uses massive amounts of stack relative to the resources of the environment it runs in.

[*] People programming in C for PICs or something, using a C compiler that is basically a non-optimizing assembler, are allowed to be offended that I've called their compiler "not worth using". The stack on such devices is so different from "typical" systems that the answer is different anyway.

How to measure the size of a C# program

This will give you the size of the program's executable in bytes from inside your program:

FileInfo fi = new FileInfo(Assembly.GetEntryAssembly().Location);
Console.WriteLine(fi.Length);

Otherwise you can just browse to the bin folder of your executable in explorer and see the size in file properties.

In c, Is it bad to have functions dedicated to allocate memory?

My question is: which is the best practice : 1) to offer a function that will allocate memory (and properly document this) as it may be convenient in come cases, or 2) this should it be left to the caller of the function.

I don't think this is a matter of best practices. There is nothing inherently wrong with a function that creates and returns (a pointer to) a new, dynamically-allocated object. For this to be more useful than allocating space directly, such a function should be sure to give the object a consistent initial value as well, though it might well do so by calling a different function. Overall, this is the C analog of C++'s new operator combined with a constructor.

That is not exclusive of provision for users to allocate objects themselves, whether dynamically or otherwise. If the type in question is public, then there may be good reason to provide an initialization function that does no allocation. As you observe, that particularly serves the purposes of code that relies on automatically or statically allocated objects.

I also read that the std function do not allocate memory dynamically, and that's why the strdup function is not standard. So I would say that the second option is the best ?

The Standard committee's policy for standard library functions cannot rationally be extended to your own functions. The ultimate outcome would be that no function anywhere should ever allocate memory dynamically, and if that were the committee's intent, then they would have at least deprecated the standard library's explicit memory allocation functions.



Related Topics



Leave a reply



Submit