Mi piacerebbe vedere il layout di memoria del mio programma in C in modo da poter capire tutti i diversi segmenti della memoria praticamente durante l'esecuzione come il cambiamento in BSS o Heap per ex?Come visualizzare il layout di memoria del mio programma in C durante l'esecuzione?
risposta
In Linux, per PID di processo, consultare /proc/PID/maps
e /proc/PID/smaps
pseudofiles. (Il processo stesso può utilizzare /proc/self/maps
e /proc/self/smaps
.)
Il loro contenuto è documentato in man 5 proc.
Ecco un esempio di come è possibile leggere il contenuto in un elenco collegato di strutture di intervallo di indirizzi.
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;
}
Un esempio di programma per utilizzare il sopra, 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;
}
e Makefile rendere costruzione semplice:
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]
nota che le tre linee frastagliate Makefile sopra must caratteri di tabulazione uso, non gli spazi. Sembra che l'editor qui converte le tabulazioni in spazi, quindi è necessario rimediare, ad esempio utilizzando
sed -e 's|^ *|\t|' -i Makefile
Se non si risolve il rientro, e utilizzare gli spazi in un Makefile, vedrete un messaggio di errore simile a *** missing separator. Stop
.
Alcuni editor convertono automaticamente una scheda nella pressione diin spazi, pertanto potrebbe essere necessario approfondire le impostazioni dell'editor di qualsiasi editor in uso. Spesso, gli editor mantengono intatto il carattere di tab incollati, quindi puoi sempre provare a incollare una scheda da un altro programma.
di compilare ed eseguire, salvare i file di cui sopra ed eseguire
make
./example 0
per stampare gli intervalli di memoria utilizzate dal programma di esempio in sé. Se si vuole vedere, ad esempio, gli intervalli di memoria usate dal demone di PulseAudio, corrono
./example $(ps -o pid= -C pulseaudio)
noti che si applicano restrizioni di accesso standard. Un utente normale può vedere solo gli intervalli di memoria dei processi eseguiti come quell'utente; in caso contrario sono necessari i privilegi di superutente (sudo
o simile).
Se sei su Linux, usa gcore per ottenere un core dump statico, fa parte di gdb ...
gcore $pid > Corefile
o
gcore -o core_dump $pid
il debug di un programma in esecuzione allegare ad esso utilizzando gdb
gdb -p 1234
poi frugare in esso. Per vedere come è spiegate
(gdb) maint info sections
Exec file:
`/home/foo/program', file type elf32-i386.
[0] 0x8048134->0x8048147 at 0x00000134: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS
[1] 0x8048148->0x8048168 at 0x00000148: .note.ABI-tag ALLOC LOAD READONLY DATA HAS_CONTENTS
[2] 0x8048168->0x804818c at 0x00000168: .note.gnu.build-id ALLOC LOAD
.....
.....
[23] 0x8049a40->0x8049ad1 at 0x00000a40: .data ALLOC LOAD DATA HAS_CONTENTS
[24] 0x8049ad1->0x8049ad4 at 0x00000ad1: .bss ALLOC
a frugare nei registri utilizzare
(gdb) info all-registers
eax 0xfffffdfc -516
ecx 0x0 0
edx 0x1 1
ebx 0xffeedc28 -1123288
esp 0xffeedc0c 0xffeedc0c
ebp 0xffeedc78 0xffeedc78
esi 0x1308 4872
edi 0x45cf 17871
.... snipped
Se volete vedere l'assemblaggio utilizzato per un uso particolare funzione di disassemble
. Può anche essere utilizzato con gli indirizzi in memoria.
(gdb) disassemble main
Dump of assembler code for function main:
0x080483f0 <+0>: lea 0x4(%esp),%ecx
0x080483f4 <+4>: and $0xfffffff0,%esp
0x080483f7 <+7>: mov $0x8048780,%edx
0x080483fc <+12>: pushl -0x4(%ecx)
0x080483ff <+15>: push %ebp
0x08048400 <+16>: mov %esp,%ebp
....
....
Un'altra alternativa è strumento pmap che scarica i memoria processo dettagli mappatura:
pmap [ -x | -d ] [ -q ] pids...
pmap -V
pmap fa parte di una raccolta procps.
Inoltre, se si è interessati alla mappatura fisica, è possibile dare un'occhiata al pagemap, reso disponibile nel recente kernel di Linux per consentire al processo di conoscerne le informazioni di memoria fisica. Potrebbe essere utile per lo sviluppo del driver dello spazio utente in cui il processo dello spazio utente deve trovare l'indirizzo fisico di un buffer come destinazione DMA.
- 1. Come è il layout di memoria di un programma C/C++?
- 2. Perché la memoria del mio programma Delphi continua a crescere?
- 3. Perché il mio programma MATLAB usa così tanta memoria?
- 4. allocazione della memoria per il programma C
- 5. Quanta memoria è il mio programma usando Java
- 6. Come posso trovare perdite di memoria nel mio programma Python?
- 7. Utilizzo memoria: il programma assegna troppa memoria
- 8. Aprire il file nell'istanza attualmente in esecuzione del mio programma?
- 9. Nuovo operatore C++ - layout di memoria
- 10. Come abilitare il core dump nel mio programma Linux C++
- 11. Layout di memoria Golang rispetto a C++/C
- 12. Layout in programma GUI Win32
- 13. Come disabilitare il layout e visualizzare il renderer in ZF2?
- 14. Come scrivere il programma durante la compilazione?
- 15. Perché l'utilizzo della memoria del mio programma non torna alla normalità dopo aver liberato memoria?
- 16. Crea il mio programma di installazione da C#?
- 17. Come profilo l'utilizzo della memoria di un programma C
- 18. Come strutturare il mio programma Perl CGI?
- 19. Come mantenere il layout di debug allo stesso modo del layout del desktop
- 20. Layout di memoria di ereditarietà multipla C++ con "Classi vuote"
- 21. Suggerisci un metodo per l'aggiornamento automatico del mio programma C#
- 22. Controllo preciso del layout della memoria in Rust?
- 23. Come visualizzare un DataTable durante il debug
- 24. Come posso profilare la memoria del programma multithread in Python?
- 25. Come utilizzo il profilo di memoria nel mio progetto
- 26. Come visualizzare le informazioni del fornitore del mio NIC?
- 27. Come rendere il mio programma un processo in background
- 28. Come posso determinare la quantità di memoria il mio programma è attualmente occupa
- 29. Ottimizzazione del layout di memoria delle istanze di classe in C++
- 30. Memoria condivisa tra programma C++ e JS
su una particolare piattaforma? – isedev
@isedev: principalmente linux –
@SuryaPrakashPatel Dai un'occhiata a GDB. Oppure usa Ida se vuoi qualcosa di visivo. – fuz