Professional Documents
Culture Documents
Version 1.0
Paging in Linux
In response, will transparently create a new copy of the page for the writing process
copy-on-write occurs on a pageby-page basis
7
Allocating Arrays
#include <stdlib.h> void * calloc (size_t nr, size_t size); Returns a pointer to a block of memory suitable for holding an array of nr elements, each of size bytes calloc( ) zeros all bytes in the returned chunk of memory
10
Resizing Allocations
#include <stdlib.h> void * realloc (void *ptr, size_t size); realloc( ) resizes the region of memory pointed at by ptr to a new size of size bytes It returns a pointer to the newly sized memory, which may or may not be the same as ptr
Freeing Memory
Dynamic allocations are permanent parts of the process address space until they are manually freed Both static and dynamic allocations, disappear when the entire process exits #include <stdlib.h> void free (void *ptr); You cannot use free( ) to free partial chunks of memory (by passing in a pointer halfway into an allocated block)
12
13
Alignment of Data
The alignment of data refers to the relation between its address and memory chunks as measured by the hardware A variable located at a memory address that is a multiple of its size is said to be naturally aligned For example, a 32-bit variable is naturally aligned if it is located in memory at an address that is a multiple of 4
14
Alignment After-effects
On some systems, a load of unaligned data results in a processor trap On other systems, accessing unaligned data is safe, but results in a degradation of performance When writing portable code, alignment issues must be avoided, and all types should be naturally aligned
15
Alignment Requirements
Memory returned via malloc( ), calloc( ), and realloc( ) be properly aligned for use with any of the standard C types On Linux, these functions always return memory that is aligned along an 8 byte boundary on 32-bit systems and a 16 byte boundary on 64-bit systems
16
Customized Alignment
Occasionally, programmers require dynamic memory aligned along a larger boundary, such as a page POSIX 1003.1d provides a function named posix_memalign( )
#include <stdlib.h> int posix_memalign (void **memptr, size_t alignment, size_t size);
17
Alignment in Structures
The alignment requirement of a structure is that of its largest constituent type Structures also introduce the need for padding Padding is, filling zeros where ever alignment is necessary The GCC option -Wpadded generates a warning whenever the compiler inserts implicit padding
18
19
Risks on Alignment
Compiler transparently handles most alignment requirements and it may hide certain potential issues Do not enable structure packing Accessing data via a pointer recast from a lesseraligned to a larger-aligned block of data can result in the processor loading data that is not properly aligned for the larger type The reverse is perfectly safe
20
Risks on Alignment
char greeting[] = Hello World"; char *c = greeting[1]; unsigned long badnews = *(unsigned long *) c;
An unsigned long is likely aligned along a four or eight byte boundary. c almost certainly sits one byte off that same boundary The load of c, when typecast, causes an alignment violation
21
Risks on Alignment
On machine architectures that can detect but not properly handle alignment violations, the kernel sends the offending process the SIGBUS signal, which terminates the process
22
Implementing Malloc
Memory allocation in glibc uses the heap segment and memory mappings malloc( ) divides the heap segment into a series of power-of-2 partitions, and satisfy allocations by returning the partition that is the closest fit to the requested size Freeing memory is as simple marking the partition as free.
If adjacent partitions are free, they can be coalesced into a single, larger partition
If the top of the heap is entirely free, the system can use brk( ) to lower the break point, returning memory to the kernel
24
Implementing Malloc
This algorithm is called a buddy memory allocation scheme It has the upside of speed and simplicity, but the downside of introducing two types of fragmentation Internal fragmentation occurs when more memory than requested is used to satisfy an allocation External fragmentation occurs when sufficient memory is free to satisfy a request, but it is split into two or more nonadjacent chunks
25
Creating a new memory mapping incurs more overhead than returning memory from the heap
glibcs malloc( ) uses the heap segment to satisfy small allocations and anonymous memory mappings to satisfy large allocations Currently, the threshold for this is 128 KB
27
28
For better zero filling performance, open fd as /dev/zero, pass it to mmap, and then close fd
29
31
32
33
Stack-Based Allocations
#include <alloca.h> void * alloca (size_t size); alloca() make a dynamic memory allocation from the stack This memory lives on the stack, and is automatically freed when the invoking function returns Dont call free() for memory allocated with alloca(). This results in inefficient stack managment
34
Stack-Based Allocations
Dont use alloca( )-allocated memory in the parameters to a function call, because the allocated memory will then exist in the middle of the stack
/* DO NOT DO THIS! */ ret = foo (x, alloca (10));
Variable-Length Arrays
C99 introduced variable-length arrays (VLAs), which are arrays whose geometry is set at runtime, and not at compile time for (i = 0; i < n; ++i) { char foo[i + 1]; /* use 'foo'... */ }
If we used alloca( ) instead of a VLA, the memory would not be freed until the function returned
37
Filling Memory
#include <string.h> void * memset (void *s, int c, size_t n); A call to memset( ) sets the n bytes starting at s to the byte c and returns s A frequent use is zeroing a block of memory Do not use memset( ) if you can use calloc( ). The latter is more efficient
38
Comparing Bytes
#include <string.h> int memcmp (const void *s1, const void *s2, size_t n); This compares the first n bytes of s1 to s2, and returns 0 if the blocks of memory are equivalent, a value less than zero if s1 is less than s2, and a value greater than zero if s1 is greater than s2
Because of structure padding comparing two structures for equivalence via memcmp( ) is unreliable
39
Moving Bytes
#include <string.h> void * memmove (void *dst, const void *src, size_t n); void * memcpy (void *dst, const void *src, size_t n); void * mempcpy (void *dst, const void *src, size_t n); memmove( ) can safely handle overlapping memory regions (say, if part of dst is inside of src) memcpy( ) faster than memmove( ), but dst and src may not overlap mempcpy( ) function performs the same as memcpy( ), except that it returns a pointer to the next byte after the last byte copied
40
Searching Bytes
#include <string.h> void * memchr (const void *s, int c, size_t n); void * memrchr (const void *s, int c, size_t n);
memchr( ) function scans the n bytes of memory pointed at by s for the character c
memrchr( ) function is the same as the memchr( ) function, except that it searches backward from the end of the n bytes pointed at by s
41
Searching Bytes
#include <string.h> void * memmem (const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
memmem( ) function returns a pointer to the first occurrence of the subblock needle, of length needlelen bytes, within the block of memory haystack, of length haystacklen bytes If the function does not find needle in haystack, it returns NULL
42
Jumbling Bytes
#include <string.h> void * memfrob (void *s, size_t n); memfrob( ) scrambles the first n bytes of memory starting at s by exclusive ORing (XORing) each byte with the number 42. The call returns s The effect of a call to memfrob( ) can be reversed by calling memfrob( ) again on the same region of memory This is not a substitute for encryption
43
Locking Memory
Linux implements demand paging, which means that pages are swapped in from disk as needed, and swapped out to disk when no longer needed Swapping hurts two things: Determinism: page faults can overrun the timing needs Security: private secrets swapped on a disk may not be acceptable in a high-security environment
44
Locking Memory
The kernel, if we trust its design, always chooses the optimal page to swap outthat is, the page least likely to be used in the future So when you change its behavior, it has to swap out a suboptimal page
45
46
47
Unlocking Memory
#include <sys/mman.h> int munlock (const void *addr, size_t len); int munlockall (void);
munlock( ) unlocks the pages starting at addr and extending for len bytes
munlockall( ) undoes the effects of mlockall( ) Memory locks do not nest. Therefore, a single mlock( ) or munlock( ) will unlock a locked page
48
Fork() Swap
When the parent process calls fork() system call, the child process is created If there is short of memory then the child process is sent to the read-to-run state in the swap device The parent process is not swapped out
When the memory will be available the child process will be swapped into the main memory
49
Opportunistic Allocation
Linux employs an opportunistic allocation strategy When a process requests additional memory from the kernel the kernel commits to the memory without actually providing any physical storage Only when the process writes to the newly allocated memory does the kernel satisfy the commitment by converting the commitment for memory to a physical allocation of memory The kernel does this on a page-by-page basis
50
Opportunistic Allocation
The amount of committed memory can far exceed the amount of physical memory and even swap space available This feature is called overcommitment
51
When overcommitment results in insufficient memory to satisfy a committed request, is called an out of memory (OOM) condition
52
54
56
==2116== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==2116== at 0x1B900DD0: malloc (vg_replace_malloc.c:131) ==2116== by 0x804840F: main (in /home/cprogram/example1)
57
58
Thank you!
59