Same address on heap for both child and parent process even after COPY_ON_WRITE??
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Same address on heap for both child and parent process even after COPY_ON_WRITE??
Hi,
While playing with fork(), I observed a scenario on which I need some clarification. Before that, here is the program code which I ran:
Code:
#include <sys/types.h>
#include <unistd.h>
int i = 0;
int *j = NULL;
int *m = NULL;
int main()
{
int k = 0;
int *l = NULL;
int *n = NULL;
j = (int *)malloc(sizeof(int));
m = (int *)malloc(sizeof(int));
l = (int *)malloc(sizeof(int));
n = (int *)malloc(sizeof(int));
*j = 1;
*m = 1;
*l = 1;
*n = 1;
printf( " g_&i=%u\tg_i=%u\th_&j=%u\th_j=%u\th_*j=%u\th_&m=%u\th_m=%u\th_*m=%u\n", &i, i, &j, j, *j, &m, m, *m );
printf( " l_&k=%u\tl_k=%u\th_&l=%u\th_l=%u\th_*l=%u\th_&n=%u\th_n=%u\th_*n=%u\n", &k, k, &l, l, *l, &n, n, *n );
if ( 0 == fork() )
{
printf( "C. g_&i=%u\tg_i=%u\th_&j=%u\th_j=%u\th_*j=%u\th_&m=%u\th_m=%u\th_*m=%u\n", &i, i, &j, j, *j, &m, m, *m );
printf( "C. l_&k=%u\tl_k=%u\th_&l=%u\th_l=%u\th_*l=%u\th_&n=%u\th_n=%u\th_*n=%u\n", &k, k, &l, l, *l, &n, n, *n );
sleep(1);
printf("\nCOPY_ON_WRITE will take place now\n\n");
i = 1;
k = 1;
*j = 2;
*m = 2;
*l = 3;
*n = 3;
printf( "C. g_&i=%u\tg_i=%u\th_&j=%u\th_j=%u\th_*j=%u\th_&m=%u\th_m=%u\th_*m=%u\n", &i, i, &j, j, *j, &m, m, *m );
printf( "C. l_&k=%u\tl_k=%u\th_&l=%u\th_l=%u\th_*l=%u\th_&n=%u\th_n=%u\th_*n=%u\n", &k, k, &l, l, *l, &n, n, *n );
}
else
{
printf( "P. g_&i=%u\tg_i=%u\th_&j=%u\th_j=%u\th_*j=%u\th_&m=%u\th_m=%u\th_*m=%u\n", &i, i, &j, j, *j, &m, m, *m );
printf( "P. l_&k=%u\tl_k=%u\th_&l=%u\th_l=%u\th_*l=%u\th_&n=%u\th_n=%u\th_*n=%u\n", &k, k, &l, l, *l, &n, n, *n );
sleep(1);
printf( "P. g_&i=%u\tg_i=%u\th_&j=%u\th_j=%u\th_*j=%u\th_&m=%u\th_m=%u\th_*m=%u\n", &i, i, &j, j, *j, &m, m, *m );
printf( "P. l_&k=%u\tl_k=%u\th_&l=%u\th_l=%u\th_*l=%u\th_&n=%u\th_n=%u\th_*n=%u\n", &k, k, &l, l, *l, &n, n, *n );
}
}
Here, I was just trying to figure out the effect of COPY_ON_WRITE on the addresses of the various kinds of variables used here after fork() and here is the output which I got:
Code:
[piyushkansal@localhost Forking]$ ./fork
g_&i=134519608 g_i=0 h_&j=134519612 h_j=166604808 h_*j=1 h_&m=134519616 h_m=166604824 h_*m=1
l_&k=3220329380 l_k=0 h_&l=3220329376 h_l=166604840 h_*l=1 h_&n=3220329372 h_n=166604856 h_*n=1
C. g_&i=134519608 g_i=0 h_&j=134519612 h_j=166604808 h_*j=1 h_&m=134519616 h_m=166604824 h_*m=1
C. l_&k=3220329380 l_k=0 h_&l=3220329376 h_l=166604840 h_*l=1 h_&n=3220329372 h_n=166604856 h_*n=1
P. g_&i=134519608 g_i=0 h_&j=134519612 h_j=166604808 h_*j=1 h_&m=134519616 h_m=166604824 h_*m=1
P. l_&k=3220329380 l_k=0 h_&l=3220329376 h_l=166604840 h_*l=1 h_&n=3220329372 h_n=166604856 h_*n=1
COPY_ON_WRITE will take place now
C. g_&i=134519608 g_i=1 h_&j=134519612 h_j=166604808 h_*j=2 h_&m=134519616 h_m=166604824 h_*m=2
C. l_&k=3220329380 l_k=1 h_&l=3220329376 h_l=166604840 h_*l=3 h_&n=3220329372 h_n=166604856 h_*n=3
P. g_&i=134519608 g_i=0 h_&j=134519612 h_j=166604808 h_*j=1 h_&m=134519616 h_m=166604824 h_*m=1
P. l_&k=3220329380 l_k=0 h_&l=3220329376 h_l=166604840 h_*l=1 h_&n=3220329372 h_n=166604856 h_*n=1
Here, I have printed the variable names by prefixing them with g_ or l_ just for an indication that its a global or local variable respectively.
Now, I have got some confusion for following variables :: j, m, l, n (all pointer variables).
1. Look at row 1, col 4 and row 1, col 7 :: j and m are two global pointer variables, to which I am allocating 4 bytes of memory using malloc, so in this case, why the difference in address (166604824 - 166604808) is of 16 bytes. It should be of 4 bytes? Same is with l and n(166604856 - 166604840 = 16)?
2. As far as I know heap is a global entity from which memory is allocated or deallocated by all the different processes. As per the fork implementation, till COPY_ON_WRITE, the same memory is used by both child and parent and after that it becomes separate. Then why even after that I am getting the same address (on heap) for both child and parent?
C :: h_j=166604808 h_j=166604824
P :: h_m=166604808 h_m=166604824
Look at row 1, col 4 and row 1, col 7 :: j and m are two global pointer variables, to which I am allocating 4 bytes of memory using malloc, so in this case, why the difference in address (166604824 - 166604808) is of 16 bytes. It should be of 4 bytes?
When you do a malloc(), additional bytes are used to keep track of how large the block is, among other things, so that when you do a free(), the library code will know how much to free, and so on. There can also be issues of aligning the memory address returned to you on a boundary of a specific power of 2.
Quote:
As far as I know heap is a global entity from which memory is allocated or deallocated by all the different processes.
Fortunately, no. Each process has its own heap, and each process has its own address space. For any specific process, a given address will map to a physical address within a block of memory allocated to the process, or will map to an address within a block of memory that has temporarily been swapped out (in which case that block of memory will be swapped back in before the process is allowed to continue), or won't map to anything belonging to the process, in which case the process will trap with a (memory) segment violation.
So if two processes have pointers whose content is identical, they won't map to the same physical memory (assuming that the "copy on write" event has occurred).
When you do a malloc(), additional bytes are used to keep track of how large the block is, among other things, so that when you do a free(), the library code will know how much to free, and so on. There can also be issues of aligning the memory address returned to you on a boundary of a specific power of 2.
So, I think the no of bytes used for this tracking will depend on the library we are using and not on OS. For eg, if I am using the same library(customized for Win) on Windows(obviously using some different system call in place of fork), then also 12 bytes will be used for tracking purpose? Or it depends on OS too?
I'm not sure I understand (all of?) your question(s) ... but ...
Quote:
C :: h_j=166604808 h_j=166604824
P :: h_m=166604808 h_m=166604824
<= Heap address "h_j=166604808" in one process maps to a completely
different physical location than identical address "h_j=166604808"
in another process
I hope that helps ...
... and apologies in advance if that doesn't address (pardon the pun) your original question...
the no of bytes used for this tracking will depend on the library we are using and not on OS. For eg, if I am using the same library(customized for Win) on Windows(obviously using some different system call in place of fork), then also 12 bytes will be used for tracking purpose? Or it depends on OS too?
Ok thanks.
Since we have already carried out discussion to this level, so I also wanted to bring one thing to your notice, just for information sharing and that is:
1. Only 4B are used for tracking purpose and not all.
2. If we are allocating less than or equal to 12B then, always 12B will be allocated for data + 4 for tracking purpose = 16B.
3. The moment we start going upwards, then data bytes are incremented by 8 + 4 for tracking i.e if I am allocating 13B, then 20B will be allocated for data(12+8) + 4 for tracking = 24B.
Here is the program by which I find out this:
Code:
#include <sys/types.h>
#include <unistd.h>
int main()
{
int *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL, *g = NULL;
a = (int *)malloc(1);
b = (int *)malloc(12);
c = (int *)malloc(13);
d = (int *)malloc(20);
e = (int *)malloc(21);
f = (int *)malloc(4);
g = (int *)malloc(1);
printf( "a=%u\tb=%u\tc=%u\td=%u\te=%u\tf=%u\tg=%u\n", a, b, c, d, e, f, g );
}
As you can see here, for "b" I allocate 12B. Still, the difference is address is 140816424-140816408=16B.
But, the moment I go for 13 in "c", it goes to 140816448-140816424=24. Now, to verify whether still 4B are for tracking, I am allocating 20B again in "d" and still the difference is 140816472-140816448=24.
I'm not sure I understand (all of?) your question(s) ... but ...
Actually, I had a doubt whether we have a global heap for all the processes or local heap, local to a process. So, that thing is clear now.
Neways, thanks for the effort.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.