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).