这些堆栈和堆内存地址有什么区别?
What is the difference in these stack and heap memory addresses?
我正在 Ubuntu 14.04 VM (Linux 3.13.0-55-generic i686) 上进行一些示例堆栈和堆分配,我对堆分配的内存地址感到困惑.
下面的 C 代码在堆栈上分配了三个 32 位无符号整数,在堆上分配了三个大小递减的 32 位、16 位和最后 8 位。
在下面的输出中我们可以看到堆栈上三个 32 位整数的内存地址相隔 4 位。 uint32_t i 在 0xbffd4818 后面的 4 个地址在 0xbffd481c 是 uint32_t j。所以我们可以在这里看到内存的每个单独字节都是可寻址的,因此每个 4 字节内存块相隔 4 个内存地址。
查看堆分配,虽然我们可以看到 uint32_t i_ptr 指向 0x99ae008 并且 malloc 请求了 4 个字节的 space,所以我预计 uint16_t j_ptr 从 0x99ae00c 开始,但它从 0x99ae018 开始。 uint8_t k_ptr 的第三次堆分配从 uint16_t i_ptr 之后的 16 个字节开始,它也在 uint32_t i_ptr.[=12= 之后的 16 个字节开始]
- 是否只是默认 OS 设置每个堆分配间隔 16 个字节?
- 为什么发生这种情况与我传递的尺寸无关
到 malloc?
- 如何在0x99ae008和0x99ae018之间容纳4个字节的信息?
C 来源:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
int main () {
register uint32_t ebp asm ("ebp");
printf("0x%x\n", ebp);
register uint32_t esp asm ("esp");
printf("0x%x\n", esp);
uint32_t i;
printf("%p\n", &i);
uint32_t j;
printf("%p\n", &j);
uint32_t k;
printf("%p\n", &k);
uint32_t *i_ptr = malloc(4);
printf("%p\n", i_ptr);
uint16_t *j_ptr = malloc(2);
printf("%p\n", j_ptr);
uint8_t *k_ptr = malloc(1);
printf("%p\n", k_ptr);
free(i_ptr);
free(j_ptr);
free(k_ptr);
return 0;
}
CLI 输出:
$ gcc -o heap2 heap2.c
$ ./heap2
0xbffd4838 // EBP
0xbffd4800 // ESP
0xbffd4818 // uint32_t i
0xbffd481c // uint32_t j
0xbffd4820 // uint32_t k
0x99ae008 // uint32_t i_ptr
0x99ae018 // uint16_t j_ptr
0x99ae028 // uint8_t k_ptr
malloc returns 类型的指针 void *
可以转换为任何其他类型的指针。所以malloc提供了满足任何类型要求的对齐。
通常 malloc returns 一个按段落对齐的地址(在大多数系统中它等于 16 个字节)。此外,malloc 分配的范围也具有最小的段落大小。所以如果你要写例如
char *p = malloc( 1 );
那么实际上 malloc 保留了 16 字节的范围。
我正在 Ubuntu 14.04 VM (Linux 3.13.0-55-generic i686) 上进行一些示例堆栈和堆分配,我对堆分配的内存地址感到困惑.
下面的 C 代码在堆栈上分配了三个 32 位无符号整数,在堆上分配了三个大小递减的 32 位、16 位和最后 8 位。
在下面的输出中我们可以看到堆栈上三个 32 位整数的内存地址相隔 4 位。 uint32_t i 在 0xbffd4818 后面的 4 个地址在 0xbffd481c 是 uint32_t j。所以我们可以在这里看到内存的每个单独字节都是可寻址的,因此每个 4 字节内存块相隔 4 个内存地址。
查看堆分配,虽然我们可以看到 uint32_t i_ptr 指向 0x99ae008 并且 malloc 请求了 4 个字节的 space,所以我预计 uint16_t j_ptr 从 0x99ae00c 开始,但它从 0x99ae018 开始。 uint8_t k_ptr 的第三次堆分配从 uint16_t i_ptr 之后的 16 个字节开始,它也在 uint32_t i_ptr.[=12= 之后的 16 个字节开始]
- 是否只是默认 OS 设置每个堆分配间隔 16 个字节?
- 为什么发生这种情况与我传递的尺寸无关 到 malloc?
- 如何在0x99ae008和0x99ae018之间容纳4个字节的信息?
C 来源:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
int main () {
register uint32_t ebp asm ("ebp");
printf("0x%x\n", ebp);
register uint32_t esp asm ("esp");
printf("0x%x\n", esp);
uint32_t i;
printf("%p\n", &i);
uint32_t j;
printf("%p\n", &j);
uint32_t k;
printf("%p\n", &k);
uint32_t *i_ptr = malloc(4);
printf("%p\n", i_ptr);
uint16_t *j_ptr = malloc(2);
printf("%p\n", j_ptr);
uint8_t *k_ptr = malloc(1);
printf("%p\n", k_ptr);
free(i_ptr);
free(j_ptr);
free(k_ptr);
return 0;
}
CLI 输出:
$ gcc -o heap2 heap2.c
$ ./heap2
0xbffd4838 // EBP
0xbffd4800 // ESP
0xbffd4818 // uint32_t i
0xbffd481c // uint32_t j
0xbffd4820 // uint32_t k
0x99ae008 // uint32_t i_ptr
0x99ae018 // uint16_t j_ptr
0x99ae028 // uint8_t k_ptr
malloc returns 类型的指针 void *
可以转换为任何其他类型的指针。所以malloc提供了满足任何类型要求的对齐。
通常 malloc returns 一个按段落对齐的地址(在大多数系统中它等于 16 个字节)。此外,malloc 分配的范围也具有最小的段落大小。所以如果你要写例如
char *p = malloc( 1 );
那么实际上 malloc 保留了 16 字节的范围。