GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana cara melihat tata letak memori program saya di C selama run-time?

Alternatif lain adalah alat pmap yang membuang detail pemetaan memori proses:

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

pmap adalah bagian dari koleksi procps.

Juga jika Anda tertarik dengan pemetaan fisik, Anda dapat melihat peta halaman, yang tersedia di Kernel Linux baru-baru ini agar proses mengetahui info memori fisiknya. Ini mungkin berguna untuk pengembangan driver ruang pengguna di mana proses ruang pengguna perlu menemukan alamat fisik buffer sebagai tujuan DMA.

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


Di Linux, untuk PID proses, lihat /proc/PID/maps dan /proc/PID/smaps pseudofiles. (Prosesnya sendiri bisa menggunakan /proc/self/maps dan /proc/self/smaps .)

Isinya didokumentasikan dalam man 5 proc.

Berikut adalah contoh bagaimana Anda dapat membaca konten ke dalam daftar tertaut dari struktur rentang alamat.

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;
}

Contoh program untuk menggunakan di atas, 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;
}

dan Makefile untuk membuatnya, sederhana:

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 example@unixlinux.online

Perhatikan bahwa tiga baris indentasi pada Makefile di atas harus gunakan karakter tab, bukan spasi. Tampaknya editor di sini mengonversi tab menjadi spasi, jadi Anda perlu memperbaikinya, misalnya dengan menggunakan

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

Jika Anda tidak memperbaiki lekukan, dan menggunakan spasi di Makefile, Anda akan melihat pesan kesalahan yang mirip dengan *** missing separator. Stop .

Beberapa editor mengonversi tab secara otomatis tekan tombol ke sejumlah ruang, jadi Anda mungkin perlu mempelajari pengaturan editor dari editor apa pun yang Anda gunakan. Sering kali, editor mempertahankan karakter tab yang ditempel, sehingga Anda selalu dapat mencoba menempelkan tab dari program lain.

Untuk mengompilasi dan menjalankan, simpan file di atas dan jalankan:

make
./example 0

untuk mencetak rentang memori yang digunakan oleh program contoh itu sendiri. Jika Anda ingin melihat, katakanlah, rentang memori yang digunakan oleh daemon PulseAudio Anda, jalankan:

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

Perhatikan bahwa pembatasan akses standar berlaku. Pengguna biasa hanya dapat melihat rentang memori dari proses yang berjalan sebagai pengguna tersebut; jika tidak, Anda memerlukan hak superuser (sudo atau serupa).


Linux
  1. Cara Menghapus Cache Memori di Linux

  2. Program Python memakan RAM

  3. Tata letak memori program di linux

  1. Bagaimana cara mengubah tata letak keyboard di i3?

  2. Bagaimana cara mengurangi penggunaan memori ClamAV?

  3. bagaimana cara mendeteksi jika isolcpus diaktifkan?

  1. Mengukur Penggunaan Ram Suatu Program?

  2. Bagaimana Cara Mengarahkan Output Program Ke File Zip??

  3. Bagaimana Pipeline Membatasi Penggunaan Memori?