CSE306 Software Quality in Practice Dr. Carl Alphonce alphonce@buffalo.edu 343 Davis Hall
These slides are a reconstruction of the lecture on Wednesday 2/ 6. They capture the main points of class, not every last detail. If you have questions, please ask away in Piazza.
Memory organization
Memory organization Each process (a running STATIC program) has a chunk of memory at its disposal. This memory is divided into "static" memory (allocated/ structured before execution begins) and "synamic" DYNAMIC memory (allocated while the program executes.
Memory organization TEXT: program The static segment is STATIC divided into a TEXT segment (holding the DATA machine language instructions of the program), and a DATA segment (which has space for statically allocated DYNAMIC memory, constants, literal values, etc).
Memory organization TEXT: program The dynamic segment is STATIC divided into STACK and a HEAP areas. DATA The HEAP is generally HEAP located adjacent to the STATIC segment, and grows "down" (to higher memory DYNAMIC addresses).
Memory organization TEXT: program The STACK is generally STATIC located at the far end of memory and grows "up" (to DATA lower memory addresses). HEAP The area between the HEAP and the STACK represents available (free) memory. DYNAMIC free memory It the HEAP and STACK collide we have an out-of- memory error. STACK
Memory organization TEXT: program The STACK holds invocation STATIC records (also called stack frames). DATA An invocation record is HEAP created whenever a function is called. It has space for the function's parameters, DYNAMIC local variables, any return free memory value, as well as bookkeeping information related to the call itself STACK (e.g. where to return to).
Memory organization TEXT: program Consider this code: STATIC void g() { … } DATA void f() { … g(); … } HEAP int main() { … f() … } DYNAMIC The invocation record for free memory main is pushed on the stack as soon as execution begins. main's record is the current/ main active one.
Memory organization TEXT: program Consider this code: STATIC void g() { … } DATA void f() { … g(); … } HEAP int main() { … f() … } DYNAMIC When f() is called, an free memory invocation record for f is pushed to the top of the stack. f main f's record is the current/ active one.
Memory organization TEXT: program Consider this code: STATIC void g() { … } DATA void f() { … g(); … } HEAP int main() { … f() … } DYNAMIC When g() is called, an free memory invocation record for g is pushed to the top of the g stack. STACK f main g's record is the current/ active one.
Memory organization TEXT: program Consider this code: STATIC void g() { … } DATA void f() { … g(); … } HEAP int main() { … f() … } DYNAMIC When g() returns its free memory invocation record is removed from the stack, an f's invocation record f becomes the current/active main one.
Memory organization TEXT: program Consider this code: STATIC void g() { … } DATA void f() { … g(); … } HEAP int main() { … f() … } DYNAMIC When f() returns its free memory invocation record is removed from the stack, an main's invocation record becomes the current/active main one.
Memory organization TEXT: program The HEAP is used for STATIC dynamic allocation of non- local data. DATA a v a J w e n In Java allocation is done addr *px HEAP using 'new', as in px = new Foo(); DYNAMIC free memory Java 's garbage collector frees heap-allocated g px addr memory when it is no STACK f longer in use. main
Memory organization TEXT: program In C allocation is done STATIC using 'malloc' (memory allocate): DATA a C v a c J o l l a m w e n e px = malloc(sizeof(*px)); addr e *px r f HEAP C is not garbage collected. 'free' must be called DYNAMIC explicitly to release unused free memory memory and make it available for re-allocation: g px addr STACK f free(px); main
Memory organization TEXT: program In either case the (local) STATIC variable px holds the address of the chunk of DATA a C v a c J o l l memory, allocated on the a m w e n e heap, which holds some addr e *px r f HEAP data. DYNAMIC free memory g px addr STACK f main
Memory organization int main() { A local variable, like x in int x = 0; the code shown, has memory for its value set . aside in the function's invocation record. . . The name of the variable, x in this case, does not return 0; exist at runtime. }
Memory organization int main() { Any read from x or write int x = 0; to x is translated into a invocation memory access at some record . offset from the current offset Stack Pointer (SP). SP . memory for value of x points to a known point SP . within an invocation record. return 0; }
program #1 #include <stdio.h> This program was shown, and the class was asked int main() { to describe what does when run. It prints the int x = 0; values 0 through 9 in this while (x < 10) { format: printf("x has value %d\n",x); x = x + 1; x has value 0 } x has value 1 x has value 2 return 0; x has value 3 } x has value 4 x has value 5 x has value 6 x has value 7 x has value 8 x has value 9
program #1 #include <stdio.h> We also discussed where in memory space for the int main() { value of variable x exists. int x = 0; The class correctly said while (x < 10) { on the stack, in the printf("x has value %d\n",x); invocation record of x = x + 1; main. } return 0; }
program #1 #include <stdio.h> We also discussed where in memory space for the int main() { value of variable x exists. int x = 0; The class correctly said while (x < 10) { on the stack, in the printf("x has value %d\n",x); invocation record of x = x + 1; main. } return 0; } In reality the value of x may exist just in a register at runtime, but for our purposes right now we don't need to be concerned about that.
program #1 #include <stdio.h> Students were asked to discuss in groups how to int main() { transform this program so that the value being int x = 0; printed was stored on the while (x < 10) { heap rather than on the printf("x has value %d\n",x); stack. x = x + 1; } The next several slides show the results. return 0; }
int main() { int *x; x = malloc … while (*x < 10) { printf("x has value %d\n",*x); *x++; } }
#include <stdio.h> #include <stdlib.h> Add required libraries: stdio.h for printf int main() { stdlib.h for malloc and sizeof int *x; x = malloc(sizeof(*x)); while (*x < 10) Complete call to malloc and sizeof to { printf("x has value %d\n",*x); allocate block of memory of correct size *x++; } on heap. }
#include <stdio.h> #include <stdlib.h> int main() { int *x; x = malloc(sizeof(*x)); while (*x < 10) { printf("x has value %d\n",*x); *x++; } } bash-3.2$ clang -std=c11 -Wall -o g1 g1.c g1.c:9:2: warning: expression result unused [-Wunused-value] *x++; ^~~~ 1 warning generated. bash-3.2$ Compilation produces a warning. It's just a warning right? Surely it's safe to ignore warnings…
#include <stdio.h> #include <stdlib.h> int main() { int *x; x = malloc(sizeof(*x)); while (*x < 10) { printf("x has value %d\n",*x); *x++; } } bash-3.2$ clang -std=c11 -Wall -o g1 g1.c g1.c:9:2: warning: expression result unused [-Wunused-value] *x++; ^~~~ 1 warning generated. bash-3.2$ ./g1 x has value 0 Running the code doesn't quite produce x has value -1879048192 x has value 0 the output expected! x has value -1879048192 x has value 0 x has value -1879048192 x has value 0 x has value -1879048192 x has value -1649213425 bash-3.2$
#include <stdio.h> #include <stdlib.h> int main() { int *x; x = malloc(sizeof(*x)); while (*x < 10) { printf("x has value %d\n",*x); *x++; } } bash-3.2$ clang -std=c11 -Wall -o g1 g1.c g1.c:9:2: warning: expression result unused [-Wunused-value] *x++; We wanted ^~~~ *x++ 1 warning generated. bash-3.2$ ./g1 to be interpreted as x has value 0 (*x)++ x has value -1879048192 to increment the value on the heap. Instead this is x has value 0 x has value -1879048192 interpreted as x has value 0 *(x++) x has value -1879048192 which means that the pointer is incremented (the address x has value 0 x has value -1879048192 stored in x is advanced sizeof(*x) bytes) and then x has value -1649213425 dereferenced. The dereferencing has no effect, hence bash-3.2$ the warning.
int *x = malloc(sizeof(int)); while (*x < 10) { printf("x has value %d\n",*x); *x=*x+1; } free(x); return 0;
#include <stdio.h> #include <stdlib.h> Add required libraries: stdio.h for printf int main() { stdlib.h for malloc and sizeof int *x = malloc(sizeof(int)); while (*x < 10) { printf("x has value %d\n",*x); *x=*x+1; Put code into body of a main function. } free(x); return 0; }
Recommend
More recommend