malloc/calloc返回的内存地址是否来自虚拟地址空间?

8
char *ptr = (char*) malloc(40);
printf("%u",ptr);

56737856 (some output)

现在,如果我没有理解错误的话,我们在上面看到的输出不是物理地址,而是虚拟地址。我理解正确吗?

有没有办法看到实际的物理地址?或者反过来(如果我上面的假设是错误的),malloc 的所有内部实现是否必须使用 jemalloc 算法?


3
printf("%p", (void *)ptr); - David Ranieri
嗯。/proc/self/maps 显示堆在虚拟地址方面的位置,但不显示物理地址。 - aschepler
@aschepler:您的意思是上面的地址来自虚拟地址范围,通常在打印时我们会看到吗? - RajSanpui
@DavidRF:所以%p是用于指针实际持有的地址,你的意思是使用%p我们可以打印物理地址? - RajSanpui
1
地址是虚拟地址。您永远不会看到物理地址 - 实际上,物理地址可以更改。 - Nik Bougalis
显示剩余3条评论
3个回答

11

在用户空间应用程序中看到的所有地址都是虚拟地址。

物理地址只与内核有关。从虚拟地址到物理地址的映射非常复杂,因为:

  • 并非所有虚拟地址都具有物理地址。(例如,未映射、懒惰地填充零或交换出去的页面没有物理地址。)
  • 物理地址可能会突然更改(例如,如果页面被交换出去再交换回来,或者如果共享页面被复制)。

除了一些非常不寻常的情况(主要与硬件操作有关),您不应该关心物理地址。


正如DavidRF在上面指出的那样,如果我理解他想说的话,我们可以使用%p格式说明符打印物理地址吗? - RajSanpui
不,%p 不是魔法。它只是打印出你传递给它的地址,并且该地址将是一个虚拟地址。 - user149341
@kingsmasher1,nops,我只是在矫正格式,使用 %p 你仍在访问操作系统映射的虚拟地址。 - David Ranieri

3
在具有虚拟内存的平台上,进程地址空间中的地址是指虚拟内存中的地址。在这种系统中,在典型的应用程序级别上,实际的物理RAM地址根本没有任何意义——即使在那个时刻它已经知道,它也可以随时变化。物理RAM地址超出了你的控制范围。因此,在典型的应用程序级别上,当人们谈论“物理地址”时,通常是指你打印的内容——进程地址空间中的地址,即虚拟地址。
不要使用"%u"来将指针传递给printf函数。使用"%p",或者至少将你的指针转换为适当大小的无符号整数类型,然后使用该类型的格式说明符。

2
有没有办法查看实际物理地址?
在x86架构的实模式中,没有内存保护,你可以得到实际的物理地址,所以你可以做一些像覆盖0x0地址的事情。
这是来自《内存管理:C/C++算法与实现》的一个代码片段,可以使运行DOS的计算机崩溃:
void main()
{
    unsigned char* ptr;
    int i;
    ptr = (unsigned char *)0x0;
    for(i = 0; i < 1024; i++)
    {
        ptr[i]=0x0;
    }
    return;
}

如果我可以引用维基百科的话:
实模式不支持内存保护、多任务处理或代码特权级。在80286发布之前,也就是引入保护模式之前,实模式是x86 CPU唯一可用的模式。为了向后兼容,所有x86 CPU在复位时都会进入实模式。

虽然这很有趣,但它根本没有回答问题。 - user149341
它回答了如何获取物理地址的问题。如果需要,我会添加注释以改进答案。 - Nobilis
1
这与Linux无关。Linux不在实模式下运行。 - user149341
1
我不同意;它只回答了一个特定情况。 - Ernest Friedman-Hill
1
它回答了问题的一部分,因为答案是“取决于情况”。如果系统是普通的桌面Linux,则有可能malloc返回虚拟页面。如果系统是某些嵌入式系统,则可能根本没有虚拟地址。Malloc是特定环境所需的。 - Devolus
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接