Memory Management. CS449 Fall 2016

Memory Management CS449 Fall 2016 Life9mes •  Life9me: 9me from which a par9cular memory loca9on is allocated un9l it is deallocated •  Three types...
Author: Aubrie Wheeler
8 downloads 0 Views 114KB Size
Memory Management CS449 Fall 2016

Life9mes •  Life9me: 9me from which a par9cular memory loca9on is allocated un9l it is deallocated •  Three types of life9mes –  Automa9c (within a scope) –  Sta9c (dura9on of program) –  Manual (explicitly controlled by programmer)

•  Manual control involves inser9ng into your code –  Alloca9on calls –  Dealloca9on calls

Manual Alloca9on Pros/Cons •  Pros (Flexibility) –  Can create storage loca9ons on demand without declaring them as variables –  Useful for construc9ng dynamic data structures (e.g. linked lists, trees, graphs) whose size and shape can change depending on user input

•  Cons (Complexity) –  Programmer has to think about the behavior of program to determine the life9mes of loca9ons

C Standard Library Func9ons •  Programmer only has to worry about when to allocate/deallocate and not how •  Just include func9ons declared in •  Takes care of the niTy-griTy details of memory management –  System calls to request memory from OS –  Keeping track of areas of allocated memory –  Keeping track of areas of free memory –  Searching for suitable area to allocate memory

Alloca9on Func9ons •  void *malloc(size_t size)

–  Allocates size bytes and returns a pointer to the allocated memory (NULL on failure) –  Memory is not cleared •  void *calloc(size_t nmemb, size_t size)

–  Allocates nmemb * size bytes and returns a pointer to the allocated memory (NULL on failure) –  Memory is set to 0

•  Check return value for out-of-memory error

Dealloca9on Func9on •  void free(void *ptr)

–  Frees the memory space pointed to by ptr, which must have been previously allocated –  Counterpart for both malloc() and calloc() –  If free() has already been called on the same loca9on, behavior is undefined

Re-Alloca9on Func9on •  void *realloc(void *ptr, size_t size)

–  Changes size of memory block pointed to by ptr to size bytes and returns that pointer (NULL on failure) –  Newly allocated memory will be unini9alized –  If ptr is NULL, same as malloc –  If size is zero, and ptr is not NULL, same as free

•  Use when you want to resize previously allocated memory without losing its contents

Malloc/Free Example

#include #include int main(int argc, char *argv[]) { int *p, i, length = atoi(argv[1]); p = (int *)malloc(length * sizeof(int)); srand((unsigned int)9me(NULL)); for(i = 0; i < length; i++) p[i] = rand(); for(i = 0; i < length; i++) prinf("%d \n", p[i]); free(p); return 0; }

>> ./a.out 5 729751416 264693780 884704288 90101471 690008936

Malloc/Free Example

#include •  #include •  int main(int argc, char *argv[]) { •  int *p, i, length = atoi(argv[1]); p = (int *)malloc(length * sizeof(int)); srand((unsigned int)9me(NULL)); for(i = 0; i < length; i++) p[i] = rand(); for(i = 0; i < length; i++) prinf("%d \n", p[i]); free(p); return 0; }

Calculate the number of bytes of memory you want to allocate using sizeof Don’t forget to free memory once you ware done using it The life9me of the loca9ons allocated using malloc() is independent of pointer p –  Pointer p is deallocated at the end of scope main() –  The malloced loca9on’s life9me ends on free()

How does malloc interact with the OS? •  C library memory management func9ons are built on top of 3 system calls: brk, mmap, and munmap •  int brk(void *addr) –  Changes program break (address of the top of the process’s heap) to addr –  Increasing program break è allocates memory –  Decreasing program break è deallocates memory •  void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) –  Allocates a new data segment of length at addr

•  C library func9ons perform memory management using memory provided by OS through system calls

Process Address Space 0x7fffffff Stack

brk (program break) Data (Heap) Globals Text (Code) 0

Tracing System Calls for malloc

#include int main(int argc, char *argv[]) { void *mem[100]; int i = 0; for(i = 0; i < 100; i++) { mem[i] = malloc(4096); } for(i = 0; i < 100; i++) { free(mem[i]); } return 0; }

>> strace ./a.out [sic] brk(0) = 0x601000 brk(0x623000) = 0x623000 brk(0x644000) = 0x644000 brk(0x665000) = 0x665000 brk(0x686000) = 0x686000 brk(0x622000) = 0x622000 [sic] • 

• 

Top of heap increases gradually, peaks at 0x686000 –  Not as many brk calls as malloc calls –  Why? C lib Increases heap in increasingly large chunks to minimize number of system calls Top of heap decreases dras9cally to 0x622000 –  When last memory chunk at top of heap is freed

Common Memory Errors •  Memory Leak

–  Forgesng to free unused memory ater pointer update –  Result: Steady rise in memory consump9on leading to degraded performance and eventual out-of-memory error

•  Double Free

–  Freeing the same memory loca9on twice –  Result: Undefined. Depends on C stdlib implementa9on.

•  Dangling Pointer

–  Accessing memory that has already been freed –  Result: Poten9al memory corrup9on when that memory is allocated for something else

•  Out-of-bounds Access

–  Accessing memory beyond the alloca9on boundary –  Result: Poten9al memory corrup9on when memory beyond boundary is allocated for something else

•  Memory errors are typically Heisenbugs (non-determinis9c bugs)

Memory Management C vs. Java •  Many more categories of memory errors in C –  Memory leak, double free, dangling pointer –  All due to fact that C has to free memory

•  Why free memory in C but not Java? –  Most applica9on-centric languages (e.g. Java, Python, JavaScript) have automa9c garbage collec9on –  See garbage collec9on slide

•  C opted for manual freeing –  To reduce execu9on 9me overhead due to GC –  To reduce memory overhead due to garbage

Memory Management Strategy •  Basic rules for alloca9on –  Allocate memory before using it (just like new in Java)

•  Basic rules for dealloca9on –  Free when memory can no longer be reached by program •  •  •  • 

That is, exactly when the last pointer referencing it is lost Freeing before: can lead to accessing freed memory Freeing ater: last pointer is gone, so no way to free! This is actually the rule used by the Java garbage collector

–  How do you know if you are the last pointer? •  Some9mes easily deducible by programmer •  Some9mes must use reference counter (how many point to you)

Valgrind •  Diagnos9c tool that detects run9me errors (memory management errors among them) •  Command: valgrind [op9ons] •  Not perfect –  Can miss errors (some9mes) –  Can report errors when there are none (rarely) –  Slows down program execu9on significantly

•  Try to detect all errors at compile 9me. Use valgrind as last resort.

Valgrind Memory Leak Example

#include >> gcc –g main.c #include >> ./a.out int main () >> valgrind --leak-check=full --track-origins=yes ./a.out { ==32563== HEAP SUMMARY: char *p = malloc(100); ==32563== in use at exit: 100 bytes in 1 blocks return 0; ==32563== total heap usage: 1 allocs, 0 frees, 100 bytes allocated } ==32563== ==32563== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==32563== at 0x4A069EE: malloc (vg_replace_malloc.c:270) ==32563== by 0x4004DC: main (main.c:5)

•  The “-g” op9on given to GCC inserts “debug symbols” to binary, enabling valgrind to locate the errors more accurately •  Shows 100 bytes of memory malloc’ed in main.c:5 is lost

Valgrind Double Free Example

#include >> gcc –g main.c #include >> ./a.out int main () >> valgrind --leak-check=full --track-origins=yes ./a.out { ==4686== Invalid free() / delete / delete[] / realloc() char *p = malloc(100); ==4686== at 0x4A063F0: free (vg_replace_malloc.c:446) free(p); ==4686== by 0x400531: main (main.c:7) free(p); ==4686== Address 0x4c37040 is 0 bytes inside a block of size 100 free'd return 0; ==4686== at 0x4A063F0: free (vg_replace_malloc.c:446) } ==4686== by 0x400525: main (main.c:6)

•  Shows memory free’d in main.c:7 has already been free’d previously in main.c:6

Valgrind Dangling Pointer Example

#include >> gcc –g main.c #include >> ./a.out int main () >> valgrind --leak-check=full --track-origins=yes ./a.out { ==4814== Invalid write of size 1 char *p = malloc(100); ==4814== at 0x40052A: main (main.c:7) free(p); ==4814== Address 0x4c37040 is 0 bytes inside a block of size 100 free'd p[0] = ‘H’; ==4814== at 0x4A063F0: free (vg_replace_malloc.c:446) return 0; ==4814== by 0x400525: main (main.c:6) }

•  Shows invalid write to memory of size 1 in main.c:7, where the memory has already been free’d previously in main.c:6

Valgrind Out-of-bounds Example

#include >> gcc –g main.c #include >> ./a.out int main () >> valgrind --leak-check=full --track-origins=yes ./a.out { ==4950== Invalid write of size 1 char *p = malloc(100); ==4950== at 0x400522: main (main.c:6) p[100] = ‘H’; ==4950== Address 0x4c370a4 is 0 bytes ater a block of size 100 alloc'd free(p); ==4950== at 0x4A069EE: malloc (vg_replace_malloc.c:270) return 0; ==4950== by 0x400515: main (main.c:5) }

•  Shows invalid write to memory of size 1 in main.c:6, where the memory is ater a block of memory previously alloc’ed in main.c:5