\documentclass{beamer}
\usetheme{linutronix}
\usepackage{german}
\usepackage[utf8]{inputenc}
\usepackage{pgf}
\usepackage{graphicx}

\title{Linux Memory Management basics}
\institute{Linutronix GmbH}

\begin{document}

\maketitle
\begin{frame}
\frametitle{Overview}
\tableofcontents
\end{frame}

\section{Basics}
\subsection{Overview}
\begin{frame}
\frametitle{Overview}
\begin{itemize}
\item over-committing
\item Copy-On-Write
\item Page relocation
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{over-committing}
\begin{itemize}
\item Comparable to those low-cost airlines ;)
\pause
\item ...selling more tickets than available seats
\pause
\item ...hoping not everyone will come ;)
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{over-commit settings}
\begin{verbatim}
/proc/sys/vm/overcommit_memory
\end{verbatim}
Possible settings are:
\begin{itemize}
\item 0: Heuristic overcommit handling (default)
\item 1: Always overcommit
\item 2: Don't overcommit
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{The OOM Killer}
...is invoked if you ask for more memory than available.\\
\pause
\textbf{Result}: The kernel kills a task
\end{frame}

\begin{frame}
\frametitle{Copy-On-Write}
\begin{itemize}
\item completely transparently for userspace
\item you don't need the same data twice
\item only updated if one virtual memory area is updated
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Page relocation}
\begin{itemize}
\item AKA paging or swapping
\item Linux can move a page to / from swap
\item also completely transparently for userspace
\end{itemize}
\end{frame}

\subsection{The stack}
\begin{frame}
\frametitle{The stack}
\begin{itemize}
\item Grows top - down
\item Configurable stack size
\item Stack grows on demand. Access beyond current size ends up in a
''Stackfault'' which is handled by the kernel
\item ulimit -a shows the current maximum stack size
\item ulimit -s \emph{size} sets the maximum stack size
\item Default maximum stack size is 8MiB
\end{itemize}
\end{frame}

\subsection{The heap}

\begin{frame}
\frametitle{The heap: Userland handling}
\begin{itemize}
\item Memory is allocated using malloc()
\item Memory is freed using free()
\item malloc() uses the mmap() and the sbrk() system calls
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{The heap: Userland handling}
\begin{itemize}
\item For small junks, malloc() allocates memory from the heap and adjusts the
size using sbrk()
\item For larger blocks (larger than defined in MMAP\_THRESHOLD) the memory is
allocated as private, anonymous mapping
\item MMAP\_THRESHOLD is 128kb by default
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{malloc()}
\begin{itemize}
\item Keep over-commit in mind!
\item If over-commit is enabled: A non-null return value from malloc() doesn't
guarantee that the memory really is available.
\end{itemize}
\end{frame}

\section{Do's and Dont's}
\subsection{The heap}
% fragmentation
% check return value
% ulimit (limit memory consumption)
\begin{frame}
\frametitle{Return value}
Always check malloc's return value!!
\end{frame}

\begin{frame}
\frametitle{How to avoid heap fragmentation}
\begin{itemize}
\item GLIBCs malloc() itself tries to avoid fragmentation
\item The allocator can't avoid fragmentation caused by a bad application
design!
\item Try to re-use memory pools
\item free memory you don't need anymore!
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{How to limit memory consumption}
ulimit:
\begin{itemize}
\item ulimit -d sets a limit for the data segment
\item ulimit -v sets a limit for the virtual memory
\item Check limits with ulimit -a
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{ulimit example}
\scriptsize
\begin{verbatim}
$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 20
file size               (blocks, -f) unlimited
pending signals                 (-i) 16382
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
\end{verbatim}
\end{frame}

\section{Realtime}
\subsection{General}
\begin{frame}[fragile]
\frametitle{Locking the memory}
\begin{verbatim}
/* Lock memory */
if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
        perror("mlockall failed");
        exit(-2);
}
\end{verbatim}
\end{frame}
\subsection{Stack}
\begin{frame}[fragile]
\frametitle{Stack prefaulting}
\begin{verbatim}
#define MAX_SAFE_STACK (8*1024)

void stack_prefault(void) {
        unsigned char dummy[MAX_SAFE_STACK];

        memset(&dummy, 0, MAX_SAFE_STACK);
        return;
}
\end{verbatim}
\end{frame}

\subsection{Heap}
\begin{frame}
\frametitle{Allocations from Realtime context}
\begin{itemize}
\item If possible, avoid memory allocations from Realtime context
\item Try to use a pre-allocated buffer
\end{itemize}
\end{frame}


\begin{frame}[fragile]
\frametitle{Disable malloc trimming and mmap usage}
\begin{verbatim}
mallopt(M_TRIM_THRESHOLD, -1);
mallopt(M_MMAP_MAX, 0);
\end{verbatim}
\end{frame}

\begin{frame}[fragile]
\frametitle{Reserve process memory}
\begin{verbatim}
static void reserve_process_memory(int size)
{
   int i;
   char *buffer;
   
   buffer = malloc(size);
   
   /* Touch each page in this piece of
    * memory to get it mapped into RAM */
   for (i = 0; i < size; i += sysconf(_SC_PAGESIZE))
      buffer[i] = 0;
   
   free(buffer);
}
\end{verbatim}
\end{frame}

\end{document}
