GNU/Linux >> Znalost Linux >  >> Linux

Jak zobrazit rozložení paměti mého programu v C za běhu?

Další alternativou je nástroj pmap, který vypíše podrobnosti o mapování paměti procesu:

    pmap [ -x | -d ] [ -q ] pids...
    pmap -V

pmap je součástí kolekce procps.

Pokud máte zájem o fyzické mapování, můžete se podívat na mapu stránek, která je k dispozici v nedávném jádře Linuxu, aby proces věděl, že jde o informace o fyzické paměti. Může to být užitečné pro vývoj ovladačů uživatelského prostoru, kde proces uživatelského prostoru potřebuje najít fyzickou adresu vyrovnávací paměti jako cíl DMA.

https://www.kernel.org/doc/Documentation/vm/pagemap.txt


V Linuxu najdete PID procesu v /proc/PID/maps a /proc/PID/smaps pseudosoubory. (Samotný proces může používat /proc/self/maps a /proc/self/smaps .)

Jejich obsah je dokumentován v man 5 proc.

Zde je příklad toho, jak můžete načíst obsah do propojeného seznamu struktur rozsahu adres.

mem-stats.h :

#ifndef   MEM_STATS_H
#define   MEM_STATS_H
#include <stdlib.h>
#include <sys/types.h>

#define PERMS_READ               1U
#define PERMS_WRITE              2U
#define PERMS_EXEC               4U
#define PERMS_SHARED             8U
#define PERMS_PRIVATE           16U

typedef struct address_range address_range;
struct address_range {
    struct address_range    *next;
    void                    *start;
    size_t                   length;
    unsigned long            offset;
    dev_t                    device;
    ino_t                    inode;
    unsigned char            perms;
    char                     name[];
};

address_range *mem_stats(pid_t);
void free_mem_stats(address_range *);

#endif /* MEM_STATS_H */

mem-stats.c :

#define _POSIX_C_SOURCE 200809L
#define _BSD_SOURCE
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "mem-stats.h"

void free_mem_stats(address_range *list)
{
    while (list) {
        address_range *curr = list;

        list = list->next;

        curr->next = NULL;
        curr->length = 0;
        curr->perms = 0U;
        curr->name[0] = '\0';

        free(curr);
    }
}

address_range *mem_stats(pid_t pid)
{
    address_range *list = NULL;
    char          *line = NULL;
    size_t         size = 0;
    FILE          *maps;

    if (pid > 0) {
        char namebuf[128];
        int  namelen;

        namelen = snprintf(namebuf, sizeof namebuf, "/proc/%ld/maps", (long)pid);
        if (namelen < 12) {
            errno = EINVAL;
            return NULL;
        }

        maps = fopen(namebuf, "r");
    } else
        maps = fopen("/proc/self/maps", "r");

    if (!maps)
        return NULL;

    while (getline(&line, &size, maps) > 0) {
        address_range *curr;
        char           perms[8];
        unsigned int   devmajor, devminor;
        unsigned long  addr_start, addr_end, offset, inode;
        int            name_start = 0;
        int            name_end = 0;

        if (sscanf(line, "%lx-%lx %7s %lx %u:%u %lu %n%*[^\n]%n",
                         &addr_start, &addr_end, perms, &offset,
                         &devmajor, &devminor, &inode,
                         &name_start, &name_end) < 7) {
            fclose(maps);
            free(line);
            free_mem_stats(list);
            errno = EIO;
            return NULL;
        }

        if (name_end <= name_start)
            name_start = name_end = 0;

        curr = malloc(sizeof (address_range) + (size_t)(name_end - name_start) + 1);
        if (!curr) {
            fclose(maps);
            free(line);
            free_mem_stats(list);
            errno = ENOMEM;
            return NULL;
        }

        if (name_end > name_start)
            memcpy(curr->name, line + name_start, name_end - name_start);
        curr->name[name_end - name_start] = '\0';

        curr->start = (void *)addr_start;
        curr->length = addr_end - addr_start;
        curr->offset = offset;
        curr->device = makedev(devmajor, devminor);
        curr->inode = (ino_t)inode;

        curr->perms = 0U;
        if (strchr(perms, 'r'))
            curr->perms |= PERMS_READ;
        if (strchr(perms, 'w'))
            curr->perms |= PERMS_WRITE;
        if (strchr(perms, 'x'))
            curr->perms |= PERMS_EXEC;
        if (strchr(perms, 's'))
            curr->perms |= PERMS_SHARED;
        if (strchr(perms, 'p'))
            curr->perms |= PERMS_PRIVATE;

        curr->next = list;
        list = curr;
    }

    free(line);

    if (!feof(maps) || ferror(maps)) {
        fclose(maps);
        free_mem_stats(list);
        errno = EIO;
        return NULL;
    }
    if (fclose(maps)) {
        free_mem_stats(list);
        errno = EIO;
        return NULL;
    }

    errno = 0;
    return list;
}

Příklad programu k použití výše uvedeného, ​​example.c :

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "mem-stats.h"

int main(int argc, char *argv[])
{
    int  arg, pid;
    char dummy;

    if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
        fprintf(stderr, "       %s PID\n", argv[0]);
        fprintf(stderr, "\n");
        fprintf(stderr, "You can use PID 0 as an alias for the command itself.\n");
        fprintf(stderr, "\n");
        return EXIT_SUCCESS;
    }

    for (arg = 1; arg < argc; arg++)
        if (sscanf(argv[arg], " %i %c", &pid, &dummy) == 1) {
            address_range *list, *curr;

            if (!pid)
                pid = getpid();

            list = mem_stats((pid_t)pid);
            if (!list) {
                fprintf(stderr, "Cannot obtain memory usage of process %d: %s.\n", pid, strerror(errno));
                return EXIT_FAILURE;
            }

            printf("Process %d:\n", pid);
            for (curr = list; curr != NULL; curr = curr->next)
                printf("\t%p .. %p: %s\n", curr->start, (void *)((char *)curr->start + curr->length), curr->name);
            printf("\n");
            fflush(stdout);

            free_mem_stats(list);

        } else {
            fprintf(stderr, "%s: Invalid PID.\n", argv[arg]);
            return EXIT_FAILURE;
        }

    return EXIT_SUCCESS;
}

a Makefile aby bylo sestavení jednoduché:

CC      := gcc
CFLAGS  := -Wall -Wextra -O2 -fomit-frame-pointer
LDFLAGS := 
PROGS   := example

.PHONY: all clean

all: clean $(PROGS)

clean:
    rm -f *.o $(PROGS)

%.o: %.c
    $(CC) $(CFLAGS) -c $^

example: mem-stats.o example.o
    $(CC) $(CFLAGS) $^ $(LDFLAGS) -o [email protected]

Všimněte si, že tři odsazené řádky v Makefile výše musí používejte znaky tabulátoru, nikoli mezery. Zdá se, že editor zde převádí tabulátory na mezery, takže to musíte opravit, například pomocí

sed -e 's|^  *|\t|' -i Makefile

Pokud odsazení neopravíte a použijete mezery v Makefile, zobrazí se chybová zpráva podobná *** missing separator. Stop .

Některé editory automaticky převádějí kartu stiskněte klávesu do několika mezer, takže se možná budete muset ponořit do nastavení editoru jakéhokoli editoru, který používáte. Editoři často ponechávají vložený znak tabulátoru nedotčený, takže můžete vždy zkusit vložit tabulátor z jiného programu.

Chcete-li zkompilovat a spustit, uložte výše uvedené soubory a spusťte:

make
./example 0

vytisknout rozsahy paměti používané samotným ukázkovým programem. Pokud chcete vidět, řekněme, rozsahy paměti používané vaším démonem PulseAudio, spusťte:

./example $(ps -o pid= -C pulseaudio)

Pamatujte, že platí standardní omezení přístupu. Normální uživatel může vidět pouze rozsahy paměti procesů, které běží jako tento uživatel; jinak potřebujete oprávnění superuživatele (sudo nebo podobně).


Linux
  1. Jak přesměrovat výstup programu do souboru ZIP?

  2. Jak potrubí omezují využití paměti?

  3. Program Python zabírá RAM

  1. Jak vymazat mezipaměť v Linuxu

  2. Jak mohu pozorovat šířku pásma paměti?

  3. Jak omezit využití paměti aplikace?

  1. Měření využití Ram programu?

  2. Jak zobrazit nejlepší procesy seřazené podle skutečného využití paměti?

  3. Rozložení paměti programu v linuxu