¿Una forma de determinar el uso de la memoria “real” de un proceso, es decir, el RSS sucio privado?

Las herramientas como ‘ps’ y ‘top’ reportan varios tipos de usos de memoria, como el tamaño de VM y el tamaño de conjunto residente. Sin embargo, ninguno de esos es el uso de la memoria “real”:

  • El código del progtwig se comparte entre varias instancias del mismo progtwig.
  • El código del progtwig de biblioteca compartida se comparte entre todos los procesos que usan esa biblioteca.
  • Algunas aplicaciones desvían procesos y comparten la memoria con ellos (por ejemplo, a través de segmentos de memoria compartida).
  • El sistema de memoria virtual hace que el informe de tamaño de VM sea prácticamente inútil.
  • RSS es 0 cuando se intercambia un proceso, por lo que no es muy útil.
  • Etcétera etcétera.

Descubrí que el RSS sucio y privado, según lo informado por Linux, es lo más parecido al uso de la memoria “real”. Esto se puede obtener sumndo todos los valores Private_Dirty en /proc/somepid/smaps .

Sin embargo, ¿otros sistemas operativos proporcionan una funcionalidad similar? si no, cuales son las alternativas? En particular, estoy interesado en FreeBSD y OS X.

En OSX, el Monitor de actividad realmente te da una buena idea.

La memoria privada es segura para la memoria que solo usa su aplicación. Por ejemplo, la memoria de stack y toda la memoria reservada dinámicamente utilizando malloc () y funciones / métodos comparables (método alloc para Objective-C) es memoria privada. Si se bifurca, la memoria privada se compartirá con su hijo, pero se marcará como copiar y escribir. Eso significa que mientras una página no sea modificada por ninguno de los procesos (padre o hijo) se compartirá entre ellos. Tan pronto como cualquiera de los procesos modifica cualquier página, esta se copia antes de que se modifique. Incluso cuando esta memoria se comparte con los niños fork (y solo se puede compartir con niños fork), aún se muestra como memoria “privada”, porque en el peor de los casos, cada página se modificará (tarde o temprano) y luego vuelve a ser privado para cada proceso nuevamente.

La memoria compartida es memoria actualmente compartida (las mismas páginas son visibles en el espacio de proceso virtual de diferentes procesos) o es probable que se comparta en el futuro (por ejemplo, memoria de solo lectura, ya que no hay razón para no compartir la lectura -sólo memoria). Al menos así es como leo el código fuente de algunas herramientas de línea de comando de Apple. Entonces, si comparte memoria entre procesos usando mmap (o una llamada comparable que mapea la misma memoria en múltiples procesos), esto sería memoria compartida. Sin embargo, el código ejecutable también es memoria compartida, ya que si se inicia otra instancia de su aplicación no hay ninguna razón por la cual no pueda compartir el código ya cargado en la memoria (las páginas de códigos ejecutables son de solo lectura por defecto, a menos que esté ejecutando aplicación en un depurador). Por lo tanto, la memoria compartida es realmente utilizada por la aplicación, al igual que la privada, pero también puede ser compartida con otro proceso (o puede que no, pero ¿por qué no se contabilizaría para su aplicación si se compartiera?)

La memoria real es la cantidad de RAM actualmente “asignada” a su proceso, no importa si es privada o compartida. Esto puede ser exactamente la sum de privado y compartido, pero generalmente no lo es. Es posible que su proceso tenga más memoria asignada de la que necesita actualmente (esto acelera las solicitudes de más memoria en el futuro), pero eso no representa ninguna pérdida para el sistema. Si otro proceso necesita memoria y no hay memoria libre disponible, antes de que el sistema comience a intercambiar, quitará esa memoria adicional de su proceso y le asignará otro proceso (que es una operación rápida e indolora); por lo tanto, su próxima llamada malloc podría ser algo más lenta. La memoria real también puede ser más pequeña que la memoria privada y física; esto se debe a que si su proceso solicita memoria del sistema, solo recibirá “memoria virtual”. Esta memoria virtual no está vinculada a ninguna página de memoria real, siempre y cuando no la utilice (por lo tanto, malloc 10 MB de memoria, use solo un byte de ella, su proceso obtendrá solo una página, 4096 byte, de memoria asignada – el rest solo se asigna si alguna vez lo necesitas). La memoria adicional que se intercambia puede no contar también para la memoria real (no estoy seguro de esto), pero contará para la memoria compartida y privada.

La memoria virtual es la sum de todos los bloques de direcciones que se consideran válidos en el espacio de proceso de sus aplicaciones. Estas direcciones pueden estar vinculadas a la memoria física (que de nuevo es privada o compartida) o no, pero en ese caso se vincularán a la memoria física tan pronto como utilice la dirección. Acceder a direcciones de memoria fuera de las direcciones conocidas causará un SIGBUS y su aplicación se bloqueará. Cuando se intercambia la memoria, el espacio de direcciones virtuales para esta memoria sigue siendo válido y el acceso a esas direcciones hace que la memoria se vuelva a intercambiar.

Conclusión:
Si su aplicación no utiliza explícita o implícitamente la memoria compartida, la memoria privada es la cantidad de memoria que su aplicación necesita debido al tamaño de la stack (o tamaños si son multiproceso) y debido a las llamadas malloc () que realizó para la memoria dinámica. No tiene que preocuparse mucho por la memoria compartida o real en ese caso.

Si su aplicación usa memoria compartida, y esto incluye una UI gráfica, donde la memoria se comparte entre su aplicación y el WindowServer, por ejemplo, entonces también puede echar un vistazo a la memoria compartida. Un número de memoria compartido muy alto puede significar que tiene demasiados recursos gráficos cargados en la memoria en este momento.

La memoria real es de poco interés para el desarrollo de aplicaciones. Si es más grande que la sum de compartido y privado, entonces esto no significa nada más que el hecho de que el sistema es perezoso en la memoria alejada de su proceso. Si es más pequeño, entonces su proceso ha solicitado más memoria de la que realmente necesitaba, lo cual tampoco está mal, ya que mientras no use toda la memoria solicitada, no estará “robando” la memoria del sistema. Si es mucho más pequeño que la sum de compartido y privado, solo puede considerar solicitar menos memoria cuando sea posible, ya que está solicitando un poco más de memoria (una vez más, esto no está mal, pero me dice que su código no es optimizado para un uso mínimo de memoria y si es multiplataforma, otras plataformas pueden no tener un manejo de memoria tan sofisticado, por lo que puede preferir asignar muchos bloques pequeños en lugar de algunos grandes, por ejemplo, o liberar memoria mucho antes, y así en).

Si aún no está satisfecho con toda esa información, puede obtener aún más información. Abra una terminal y ejecute:

 sudo vmmap  

¿Dónde está la identificación del proceso de su proceso? Esto le mostrará las estadísticas de CADA bloque de memoria en su espacio de proceso con dirección inicial y final. También le indicará de dónde proviene este recuerdo (¿Un archivo mapeado? ¿Memoria de stack? ¿Memoria Malloc? ¿Una sección __DATA o __TEXT de su ejecutable?), Qué tan grande es en KB, los derechos de acceso y si es privado, compartido o copiado sobre escritura. Si se mapea desde un archivo, incluso le dará la ruta al archivo.

Si solo desea el uso de RAM “real”, use

 sudo vmmap -resident  

Ahora se mostrará para cada bloque de memoria cuán grande es el bloque de memoria en la práctica y qué cantidad está realmente presente en la memoria física.

Al final de cada volcado también hay una tabla de resumen con las sums de diferentes tipos de memoria. Esta tabla se ve así para Firefox ahora mismo en mi sistema:

 REGION TYPE [ VIRTUAL/RESIDENT] =========== [ =======/========] ATS (font support) [ 33.8M/ 2496K] CG backing stores [ 5588K/ 5460K] CG image [ 20K/ 20K] CG raster data [ 576K/ 576K] CG shared images [ 2572K/ 2404K] Carbon [ 1516K/ 1516K] CoreGraphics [ 8K/ 8K] IOKit [ 256.0M/ 0K] MALLOC [ 256.9M/ 247.2M] Memory tag=240 [ 4K/ 4K] Memory tag=242 [ 12K/ 12K] Memory tag=243 [ 8K/ 8K] Memory tag=249 [ 156K/ 76K] STACK GUARD [ 101.2M/ 9908K] Stack [ 14.0M/ 248K] VM_ALLOCATE [ 25.9M/ 25.6M] __DATA [ 6752K/ 3808K] __DATA/__OBJC [ 28K/ 28K] __IMAGE [ 1240K/ 112K] __IMPORT [ 104K/ 104K] __LINKEDIT [ 30.7M/ 3184K] __OBJC [ 1388K/ 1336K] __OBJC/__DATA [ 72K/ 72K] __PAGEZERO [ 4K/ 0K] __TEXT [ 108.6M/ 63.5M] __UNICODE [ 536K/ 512K] mapped file [ 118.8M/ 50.8M] shared memory [ 300K/ 276K] shared pmap [ 6396K/ 3120K] 

¿Qué nos dice esto? Por ejemplo, el binario de Firefox y toda la biblioteca que carga tienen 108 MB de datos juntos en sus secciones __TEXT, pero actualmente solo 63 MB de ellos residen actualmente en la memoria. El soporte de fonts (ATS) necesita 33 MB, pero solo unos 2,5 MB están realmente en la memoria. Utiliza un poco más de 5 MB de copias de respaldo CG, CG = Núcleo de gráficos, esos son más probable contenido de ventana, botones, imágenes y otros datos que se almacenan en caché para un dibujo rápido. Ha solicitado 256 MB a través de llamadas malloc y actualmente 247 MB ​​están realmente asignados a páginas de memoria. Tiene 14 MB de espacio reservado para las stacks, pero solo el espacio de la stack de 248 KB realmente está en uso en este momento.

vmmap también tiene un buen resumen sobre la mesa

 ReadOnly portion of Libraries: Total=139.3M resident=66.6M(48%) swapped_out_or_unallocated=72.7M(52%) Writable regions: Total=595.4M written=201.8M(34%) resident=283.1M(48%) swapped_out=0K(0%) unallocated=312.3M(52%) 

Y esto muestra un aspecto interesante del OS X: para la memoria de solo lectura no juega ningún papel si se intercambia o simplemente no se asigna; solo hay residente y no residente. Para la memoria grabable esto hace la diferencia (en mi caso, el 52% de toda la memoria solicitada nunca se ha utilizado y está sin asignar, el 0% de la memoria se ha intercambiado en el disco)

En Linux, es posible que desee los números de PSS (tamaño de conjunto proporcional) en / proc / self / smaps. El PSS de un mapeo es su RSS dividido por el número de procesos que usan ese mapeo.

Top sabe cómo hacer esto. Muestra VIRT, RES y SHR por defecto en Debian Linux. VIRT = SWAP + RES. RES = CÓDIGO + DATOS. SHR es la memoria que se puede compartir con otro proceso (biblioteca compartida u otra memoria).

Además, la memoria “sucia” es meramente memoria RES que se ha utilizado y / o no se ha intercambiado.

Puede ser difícil de decir, pero la mejor forma de entenderlo es observar un sistema que no se está intercambiando. Entonces, RES – SHR es la memoria exclusiva del proceso. Sin embargo, esa no es una buena manera de verlo, porque no sabe que la memoria en SHR está siendo utilizada por otro proceso. Puede representar páginas de objetos compartidos no escritas que solo utiliza el proceso.

Realmente no puedes.

Quiero decir, memoria compartida entre procesos … ¿vas a contarlo o no? Si no lo cuentas, estás equivocado; la sum del uso de la memoria de todos los procesos no va a ser el uso total de la memoria. Si lo cuenta, lo contará dos veces; la sum no será correcta.

Yo, estoy contento con RSS. Y sabiendo que realmente no puedes confiar en eso por completo …

Puede obtener un RSS privado sucio y privado limpio de / proc / pid / smaps

Echa un vistazo a smem. Le dará información de PSS

http://www.selenic.com/smem/

 for i in /proc/[0-9]*; do grep -q 'Private_Dirty' $i/smaps; if [ $? -ne 0 ]; then continue; fi; echo -n "${i}: "; awk '/Private_Dirty/ {print $2,$3}' $i/smaps | sed 's/ tB/*1024 gB/;s/ gB/*1024 mB/;s/ mB/*1024 kB/;s/ kB/*1024/;1!s/^/+/;' | tr -d '\n' | sed 's/$/\n/' | bc | tr -d '\n'; echo; done | sort -n -k 2 

Para una pregunta que menciona Freebsd, sorprendió que nadie haya escrito esto todavía:

Si desea un estilo de Linux / proc / PROCESSID / resultado de estado, haga lo siguiente:

 mount -t linprocfs none /proc cat /proc/PROCESSID/status 

Al menos en FreeBSD 7.0, el assembly no se hizo por defecto (7.0 es una versión mucho más antigua, pero por algo tan básico, ¡la respuesta estaba oculta en una lista de correo!)

Échale un vistazo, este es el código fuente de gnome-system-monitor, cree que la memoria ” realmente utilizada ” por un proceso es sum (información- info->mem ) de X Server Memory (información- info->memxserver ) y info->memxserver Memory ( info->memwritable ), la ” Memoria que se puede info->memwritable ” es los bloques de memoria que están marcados como ” Private_ Dirty” en el archivo / proc / PID / smaps .

Aparte del sistema de Linux, podría ser de una manera diferente según el código gnome-system-monitor.

 static void get_process_memory_writable (ProcInfo *info) { glibtop_proc_map buf; glibtop_map_entry *maps; maps = glibtop_get_proc_map(&buf, info->pid); gulong memwritable = 0; const unsigned number = buf.number; for (unsigned i = 0; i < number; ++i) { #ifdef __linux__ memwritable += maps[i].private_dirty; #else if (maps[i].perm & GLIBTOP_MAP_PERM_WRITE) memwritable += maps[i].size; #endif } info->memwritable = memwritable; g_free(maps); } static void get_process_memory_info (ProcInfo *info) { glibtop_proc_mem procmem; WnckResourceUsage xresources; wnck_pid_read_resource_usage (gdk_screen_get_display (gdk_screen_get_default ()), info->pid, &xresources); glibtop_get_proc_mem(&procmem, info->pid); info->vmsize = procmem.vsize; info->memres = procmem.resident; info->memshared = procmem.share; info->memxserver = xresources.total_bytes_estimate; get_process_memory_writable(info); // fake the smart memory column if writable is not available info->mem = info->memxserver + (info->memwritable ? info->memwritable : info->memres); } 

Use la llamada al sistema de mincore (2). Citando la página man:

 DESCRIPTION The mincore() system call determines whether each of the pages in the region beginning at addr and continuing for len bytes is resident. The status is returned in the vec array, one character per page. Each character is either 0 if the page is not resident, or a combination of the following flags (defined in ):