Assume we have a Struct NODE with
typedef struct tNODE {
struct tNODE* parent;
char* inner_text;
}NODE;
Here we have a Read-Only Memory usage of initialization
NODE* temp = new_node(parent);
temp->inner_text = "something";
Vs. Heap Memory usage of initialization
NODE* temp = new_node(parent);
temp->inner_text = strdup("something");
So what I am doing in my program is that, I am parsing through an XML file(the original node struct has more components).
My question is that if I am using read-only memory I have noticed from Valgrind that the total Heap usage is a bit lower than when I am using Heap Allocation.
Is that always true ? why is that ? I work with large files(>3GB), should I take that into consideration ?
CodePudding user response:
In your "Heap Memory usage" example ...
NODE* temp = new_node(parent); temp->inner_text = strdup("something");
... you require at least double the storage for the string, because you actually have two. strdup()
will dynamically allocate memory for a copy of the contents of the string literal, but you still have the string literal too (else, what do you think strdup()
could copy from?).
This is not a question of string literal vs. not. I anticipate that you would observe similar memory usage (in both examples) if you replaced the string literal with an explicit, modifiable array such as this:
char something[] = {'s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', '\0'};
If the underlying question is about how to initialize modifiable arrays, then you would probably find this more convenient:
char something[] = "something";
If that appears at file scope, then there is a fair chance that no additional storage is consumed beyond that for your writable array.
CodePudding user response:
The string "something"
is (obviously) known at compile time, right?
So, instead of assigning a string literal, introduce a global variable like const char *something = "something";
and assign that to the field of the node.
Even if you assign the (literal) same string, the compiler will probably figure this out and will take care of the above step.
At least GCC (12.2.0) does that on my system, test it out:
struct foo { char *value; };
void processFoo(struct foo *bar)
{
printf("%p\n", bar->value);
}
int main()
{
struct foo f1 = { .value = "hello" };
processFoo(&f1);
struct foo f2 = { .value = "hello" };
processFoo(&f2);
printf("\n");
for (int i=0; i < 3; i) {
struct foo *bar = malloc(sizeof(struct foo));
bar->value = "hello";
processFoo(bar);
free(bar);
}
return 0;
}
Output:
0x55b6389f4008
0x55b6389f4008
0x55b6389f4008
0x55b6389f4008
0x55b6389f4008