当前位置: 首页 > 面试题库 >

什么存储在堆上,什么存储在堆上?

邓崇凛
2023-03-14
问题内容

任何人都可以用C,C ++和Java清楚地解释一下。什么都在堆栈上,什么都在堆上以及何时分配。

我所知道的,

每个函数调用的所有局部变量(无论是基元,指针还是引用变量)都在新的堆栈框架上。

使用new或malloc创建的所有内容都会进入堆。

我对几件事感到困惑。

是在堆上创建的对象成员的引用/基元是否也存储在堆上?

以及在每个框架中递归创建的方法的那些本地成员呢?它们都在堆栈上吗?如果是,那么在运行时是否分配了堆栈内存?同样对于文字,它们是否属于代码段?以及C中的全局变量,C
++ / Java中的static和C中的static。


问题答案:

内存中程序的结构

以下是任何程序在装入内存后的基本结构。

 +--------------------------+
 |                          |
 |      command line        |
 |        arguments         |
 |    (argc and argv[])     |
 |                          |
 +--------------------------+
 | Stack                    |
 | (grows-downwards)        |
 |                          |
 |                          |
 |                          |
 |         F R E E          |
 |        S P A C E         |
 |                          |
 |                          |
 |                          |
 |                          |
 |     (grows upwards) Heap |
 +--------------------------+
 |                          |
 |    Initialized data      |
 |         segment          |
 |                          |
 +--------------------------+
 |                          |
 |     Initialized to       |
 |        Zero (BSS)        |
 |                          |
 +--------------------------+
 |                          |
 |      Program Code        |
 |                          |
 +--------------------------+

需要注意的几点:

  • 数据段
    • 初始化的数据段(由程序员初始化为显式初始化程序)
    • 未初始化的数据段(已初始化为零数据段-BSS [以符号开头的块])
  • 代码段
  • 堆和堆区域

数据段

数据段包含由包含初始化值的用户显式初始化的全局和静态数据。

数据段的另一部分称为BSS(因为旧的IBM系统将该段初始化为零)。这是操作系统将内存块初始化为零的内存部分。这就是未初始化的全局数据和静态如何将默认值设为零。该区域是固定的,并且具有静态大小。

基于显式初始化,数据区域被分为两个区域,因为要初始化的变量可以被一对一地初始化。但是,未初始化的变量不需要用0的一对一显式初始化。取而代之的是,初始化变量的工作留给操作系统。批量初始化可以大大减少加载可执行文件所需的时间。

大多数情况下,数据段的布局在底层操作系统的控制之下,但仍有一些加载程序将部分控制权交给用户。该信息在诸如嵌入式系统的应用中可能是有用的。

可以使用代码中的指针来寻址和访问该区域。自动变量在每次需要它们时都具有初始化变量的开销,并且需要代码来进行该初始化。但是,数据区域中的变量没有这样的运行时过载,因为初始化仅执行一次,并且在加载时也进行一次。

代码段

程序代码是可执行代码可用于执行的代码区域。该区域的大小也固定。只能通过函数指针访问,不能通过其他数据指针访问。此处要注意的另一个重要信息是,系统可能将此区域视为只读存储区域,并且任何在该区域中进行写入的尝试都将导致未定义的行为。

常量字符串可以放置在代码或数据区域中,具体取决于实现方式。

尝试写入代码区域会导致未定义的行为。例如(下面我仅给出C一些示例),以下代码可能会导致运行时错误,甚至使系统崩溃。

int main()
{
    static int i;
    strcpy((char *)main,"something");
    printf("%s",main);
    if(i++==0)
    main();
}

堆放区

为了执行,程序使用了两个主要部分,即堆栈和堆。堆栈帧是在堆栈中创建的,用于功能;在堆栈中创建的是用于动态内存分配。堆栈和堆是未初始化的区域。因此,存储器中发生的任何事情都将成为在该空间中创建的对象的初始(垃圾)值。

让我们看一个示例程序,以显示哪些变量存储在哪里,

int initToZero1;
static float initToZero2;
FILE * initToZero3; 
// all are stored in initialized to zero segment(BSS)

double intitialized1 = 20.0;
// stored in initialized data segment

int main()
{
    size_t (*fp)(const char *) = strlen;
    // fp is an auto variable that is allocated in stack
    // but it points to code area where code of strlen() is stored

    char *dynamic = (char *)malloc(100);
    // dynamic memory allocation, done in heap

    int stringLength;
    // this is an auto variable that is allocated in stack

    static int initToZero4; 
    // stored in BSS

    static int initialized2 = 10; 
    // stored in initialized data segment

    strcpy(dynamic,”something”);    
    // function call, uses stack

    stringLength = fp(dynamic); 
    // again a function call 
}

还是考虑一个更复杂的例子,

// command line arguments may be stored in a separate area  
int main(int numOfArgs, char *arguments[])
{ 
    static int i;   
    // stored in BSS

    int (*fp)(int,char **) = main;  
    // points to code segment

    static char *str[] = {"thisFileName","arg1", "arg2",0};
    // stored in initialized data segment

    while(*arguments)
        printf("\n %s",*arguments++);

    if(!i++)
        fp(3,str);
}

希望这可以帮助!



 类似资料:
  • 主要内容:src/runoob/heap/MaxHeap.java 文件代码:一、概念及其介绍 堆(Heap)是计算机科学中一类特殊的数据结构的统称。 堆通常是一个可以被看做一棵完全二叉树的数组对象。 堆满足下列性质: 堆中某个节点的值总是不大于或不小于其父节点的值。 堆总是一棵完全二叉树。 二、适用说明 堆是利用完全二叉树的结构来维护一组数据,然后进行相关操作,一般的操作进行一次的时间复杂度在 O(1)~O(logn) 之间,堆通常用于动态分配和释放程序所使用的对象。 若

  • 问题内容: 假设我有两个陈述。 哪个是堆栈内存,哪个存储在堆中? 两者之间有什么区别? 创建了多少个对象,内存中的引用如何? 最佳做法是什么? 问题答案: 所有对象都存储在堆中(包括其字段的值)。1个 局部变量(包括参数)始终包含原始值或引用,并存储在堆栈中。1个 因此,对于您的两行: 您将在堆上有两个对象(两个包含的String对象)和两个引用(每个对象一个)在堆栈上(提供且是局部变量)。 (实

  • 我使用GraphDB来存储我的三元组,需要将SpinSail组件堆叠在GraphDB上,以支持自旋规则以及GraphDB默认支持的所有其他功能。 到目前为止,我已经成功地在远程服务器上创建了一个支持Spin规则的存储库(详细信息如下),但它似乎只支持Spin,而不支持GraphDB支持的其他功能(例如查看图表、通过文件添加三元组、搜索等) 创建存储库后,配置文件如下所示: 虽然一个普通的配置文件(

  • 问题内容: 我设法在目录下找到了容器,但是找不到图像。 什么是目录和文件? 问题答案: 目录的内容根据Docker用于存储的驱动程序而有所不同。 默认情况下,这将是,但可以回落到,,,或者根据您的内核支持。在大多数地方,这是可以的,但是RedHats却接受了。 您可以使用Docker守护程序的或选项手动设置存储驱动程序。 将包含驱动程序特定的图像内容存储。 现在在和文件中仅包含有关图像的元数据。

  • 问题内容: 我有一个这样的数组声明: 这是原始类型的数组。该数组存储在哪里?它存储在堆还是堆栈上?这是一个原始类型,所有原始类型都不存储在堆上。 问题答案: 正如gurukulki所说,它存储在堆中。但是,你的帖子提出了一个误解,可能是由于一些善意的人传播了“原始生物始终存在”的神话。这是不正确的。局部变量在堆栈上有其值,但并非所有原始变量都是局部的… 例如,考虑一下: 现在,住在哪里?神话暗示它

  • 我并不了解Java特别是Java调试,但在Jenkins中使用Monitoring进行堆转储,然后在Eclipse中使用MAT对其进行解码,显示总内存使用量为169.4MB,而在Jenkins中Monitoring似乎经常使用内存,GCs也经常运行。-XMX是4G。 为什么我只有169.4MB的mat?可能是因为在进行转储之前,Jenkins执行了GC吗?如果是,我是否可以避免它以看到完整的内存转