Does an Unused Member Variable Take Up Memory

Does an unused member variable take up memory?

The golden C++ "as-if" rule1 states that, if the observable behavior of a program doesn't depend on an unused data-member existence, the compiler is allowed to optimized it away.

Does an unused member variable take up memory?

No (if it is "really" unused).


Now comes two questions in mind:

  1. When would the observable behavior not depend on a member existence?
  2. Does that kind of situations occurs in real life programs?

Let's start with an example.

Example

#include <iostream>

struct Foo1
{ int var1 = 5; Foo1() { std::cout << var1; } };

struct Foo2
{ int var1 = 5; int var2; Foo2() { std::cout << var1; } };

void f1() { (void) Foo1{}; }
void f2() { (void) Foo2{}; }

If we ask gcc to compile this translation unit, it outputs:

f1():
mov esi, 5
mov edi, OFFSET FLAT:_ZSt4cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
f2():
jmp f1()

f2 is the same as f1, and no memory is ever used to hold an actual Foo2::var2. (Clang does something similar).

Discussion

Some may say this is different for two reasons:

  1. this is too trivial an example,
  2. the struct is entirely optimized, it doesn't count.

Well, a good program is a smart and complex assembly of simple things rather than a simple juxtaposition of complex things. In real life, you write tons of simple functions using simple structures than the compiler optimizes away. For instance:

bool insert(std::set<int>& set, int value)
{
return set.insert(value).second;
}

This is a genuine example of a data-member (here, std::pair<std::set<int>::iterator, bool>::first) being unused. Guess what? It is optimized away (simpler example with a dummy set if that assembly makes you cry).

Now would be the perfect time to read the excellent answer of Max Langhof (upvote it for me please). It explains why, in the end, the concept of structure doesn't make sense at the assembly level the compiler outputs.

"But, if I do X, the fact that the unused member is optimized away is a problem!"

There have been a number of comments arguing this answer must be wrong because some operation (like assert(sizeof(Foo2) == 2*sizeof(int))) would break something.

If X is part of the observable behavior of the program2, the compiler is not allowed to optimized things away. There are a lot of operations on an object containing an "unused" data-member which would have an observable effect on the program. If such an operation is performed or if the compiler cannot prove none is performed, that "unused" data-member is part of the observable behavior of the program and cannot be optimized away.

Operations that affect the observable behavior include, but are not limited to:

  • taking the size of a type of object (sizeof(Foo)),
  • taking the address of a data member declared after the "unused" one,
  • copying the object with a function like memcpy,
  • manipulating the representation of the object (like with memcmp),
  • qualifying an object as volatile,
  • etc.

1)

[intro.abstract]/1

The semantic descriptions in this document define a parameterized nondeterministic abstract machine. This document places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.

2) Like an assert passing or failing is.

Memory use of one-time use class member variables

My question: Will bar exist in memory for the lifetime of a Foo object,

Yes.

or will the compiler free up the memory bar occupies after construction of the Foo object?

No.

If bar uses dynamic memory allocation and supports move semantics (like a vector or string etc), you could however free the resources it's allocated.

Foo::Foo() {
// use bar
// .
// .
// .
decltype(bar) dummy = std::move(bar);
}

Here the dynamically allocated resources are moved out from bar into dummy. dummy then goes out of scope and destroys them.

Do unused local variables in a method acquire memory in JVM?

This is the kind of question that's worth examining with javap.

public class Foo
{
public int bar(){

System.out.println("foo");
return 8;
}
public int foo(){

int x;
System.out.println("foo");
return 8;
}
}

Notice that the difference between foo() and bar() is that one declares a local variable x and the other does not.

Now look at the jvm code (use javap -v Foo to see this on your machine)

  public int bar();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String foo
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: bipush 8
10: ireturn
LineNumberTable:
line 6: 0
line 7: 8

public int foo();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String foo
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: bipush 8
10: ireturn
LineNumberTable:
line 12: 0
line 13: 8
}

The interesting thing is that the line-by-line output is identical, but the locals for bar is 1, and for foo it's 2. So it looks like space is indeed allocated for x, even though the compiler output doesn't ever use it.

UPDATE: Doing a bit more research on this, I find this page which suggests to me that, although the compiled bytecode implies that space is allocated for x, it may indeed be optimized away by the jvm. Unfortunately, I find no complete description of the optimizations performed. Particularly, the JVM documentation chapter on compiling does not mention removing unused variables from the stack. So, barring further discoveries, my answer would be that it's implementation-dependent, but it seems like the sort of optimization that any self-respecting compiler would perform.
Notice too that it doesn't matter that much that this is a local variable rather than a field - in fact, local variables are the ones most likely to be optimized away, since they are the easiest to analyze and eliminate. (precisely because they are local)

Consecutive layout of member variables in memory?

Is it a universal rule that C++ stores variables in memory in the same order as are in the source?

No. Such rule does not exist in C++ for variables in general.

However, member variables with same access control are stored in the same order as declared, yes. The order between members with different access control is unspecified.

Consecutive layout of member variables in memory?

There is no guarantee of the members being in consecutive memory. There may be unused padding bytes between the members, which may be required for example to satisfy the alignment requirement of the members.

If we add additional restrictions of same access control and that the members have same alignment, then effectively they are likely going to be in consecutive memory in practice, although that is not guaranteed by the language.

Is memory allocated for unused fields in Java?

Several possible scenarios:

  • If you are not using a class, then
    the class itself is not loaded in a
    class loader at all.

  • If you are using a class, but not
    instantiating it, then instance
    variables are not occupying memory since there is no instance to begin with.

  • If you are using a class, and using
    an object which is instance of that
    class, then instance variables are
    using up memory for each instance,
    regardless of whether you use these
    values or not.

Does a variable of an object use memory space if declared but not initialised?

I have to disagree a bit:

private float connection[];
private float bias;

The first one (the array) is a reference type. In other words: a (potential) pointer to some memory area. Obviously: as long as that pointer points to null ("nowhere"), no extra memory is required.

But make no mistake, your object itself needs to fit into memory. Meaning: when you instantiate a new Neuron object, then the JVM requests exactly that amount of memory it needs to store a Neuron object. This means: there is a bit of memory allocated to fit that array reference into it, and of course: the memory for your float primitive values, they are all immediately allocated.

It doesn't matter whether you have 0 or 100.00 or 10394.283 stored in that member field: because the JVM made sure that you have enough memory to fit in the required bits and bytes.

Thus: when you really have millions of objects, each float field in your object adds 32 bits. No matter where the value within that field is coming from.

Sure, if your arrays will later hold 5 or 10 or 1000 entries, then that will make up most of your memory consumption. But initially, when you just create millions of "empty" Neuron objects, you have to "pay" for each and any field that exists in your class.

Meaning: when only 1 out of 100 Neuron object will ever need these two fields, then you could decide to have:

  • A BaseNeuron class that doesn't have all 4 fields
  • one or more classes deriving from that class, adding the fields they need

Also note that this can also be the better choice from a design perspective: "empty" values always mean: extra code to deal with that. Meaning: if that array can be null ... then of course, all code dealing with that field has to check whether the array is null before using it. Compare that to: a class not having that array, versus a class where you know that the array is always set and ready to use.

I am not saying that you absolutely must change your design, but as explained: you can reduce your memory footprint, and you could make your design more clear by doing so.

How much memory does a Java object use when all its members are null?

No, you need either 4 or 8 bytes ( depending whether it's a 32 or 64 bit system ) for each null you are storing in a field. How would the object know its field was null if there wasn't something stored somewhere to tell it so?

In which memory segment the member variables reside?

It's the same as any other variable. It's not really specified in the standard, but if you create a local class instance it'll generally reside on the stack, and if you new it, it'll reside in the free store. The member variables are just inside the instance as you'd expect. Static class variables will likely reside in one of the data segments.

Non-static instances don't reside anywhere "after compilation", they get created at run time.

memory for unassigned variables in C#

It is not unassigned. All classes/structs receive their default value. For a string it is null.

If it is a local variable, then optimisation will tend to remove it. If its an instance variable then memory will be allocated (I think, C# spec is unclear).



Related Topics



Leave a reply



Submit