【问题标题】:why memory for primitive data types is not allocated? [duplicate]为什么未分配原始数据类型的内存? [复制]
【发布时间】:2014-07-06 17:58:42
【问题描述】:

原始数据类型,如 char、bool 和 int 有一些内存。假设 char,它有 1 个字节的内存。当我们在代码中使用 char 变量时,该变量必须需要 1 个字节的内存。在这种情况下我们为什么不分配内存。由于我们从不为它分配内存,它如何使用内存,即在这种情况下,CPU 是否为它分配内存。另外,我在某处读到原始数据类型被放入堆栈并在为其完成工作时被删除。什么样的堆栈?在这种情况下,堆栈是如何形成的?

【问题讨论】:

标签: objective-c cocoa memory memory-management primitive-types


【解决方案1】:

当我们创建一个NSString * 变量时,我们也不为此分配内存。

我们仅在调用alloc 时分配内存,无论是直接由我们调用还是在我们调用的方法内部。

NSString 对象存在于我们分配的内存堆中,但NSString * 变量(即指向NSString 对象的指针)存在于我们未分配的堆栈内存中。

例如,给定这两个变量:

NSString *stringOne;
NSString *stringTwo;

到目前为止,它们都没有在堆上分配任何内存,尽管它们确实存在于内存中,就像charBOOLint 存在于内存中一样。

NSString *stringOne = [[NSString alloc] initWithString:@"Hello world"];
NSString *stringTwo = stringOne;

现在发生了什么?我们在堆上为NSString 对象分配了一些内存。然后我们初始化这个内存来表示字符串“Hello world”,然后返回一个指向这个对象的指针并将它分配给stringOne

接下来,我们简单地将该指针复制到我们用于stringTwo 的堆栈内存中。我们没有在堆上分配任何额外的内存。我们只是让我们的两个字符串变量指向堆上相同的分配内存。

question and answer jsd linked in the comments 对堆栈和堆内存有更多解释,这将回答您的一些问题。

还值得注意的是,许多其他编程语言(例如 C++)允许在堆栈上创建对象,在这种情况下,我们不会像处理堆对象那样分配它们。它们确实存在于内存中,只是更类似于原始数据类型。

【讨论】:

  • 对...一个相关的实现细节(但无论如何,无论如何都不会使答案无效); [[NSString alloc] initWithString:@"Hello world"] 实际上不会在堆上创建字符串。它只会返回编译器在 mach-o 文件中设置的 __NSCFConstantString (或任何名称)。这只是一个有趣的细节,因为它不会改变您对所述字符串的消费;应该像对待任何其他对象一样对待它。
  • 我想这个例子可能更适合可变对象,因为它们的大小需要能够改变,所以更重要的是它们在堆上。
【解决方案2】:

存在过于简单化的风险,数据的内存分为三类:1) 静态,2) 堆栈 3) 堆。

它们以不同的方式分配。

如果你有

 static char something ;

在函数中定义或

char something ;

在函数之外,该数据由链接器使用来自编译器的指令定义并由程序加载器分配。

几乎现有的每个处理器都使用堆栈来支持嵌套数据(例如,函数调用)。堆栈是存在于每个进程(以及每个处理器模式)的内存块。有一个称为堆栈指针的硬件寄存器,用于标识堆栈的当前位置。通常 SP 从堆栈的高端开始并向下工作。为了在堆栈上分配内存,程序从堆栈指针中减去所需的字节数。要解除分配,它会添加到堆栈指针。分配和释放总是在同一端进行。

堆栈上有两个操作。 PUSH 意味着将某些东西放在堆栈上。 POP 将其删除。大多数处理器都有 PUSH 和 POP 指令

如果你有

 char something

在函数中定义,该内存由程序按照编译器的指示分配,方法是执行类似的操作来调整堆栈指针(我现在省略了帧指针)

 SUB   BYTESNEEDED, SP

进入函数并通过doing释放

ADD BYTESNEEDED, SP

在离开函数之前。在函数执行期间,局部变量位于堆栈指针的偏移量处。

这通常通过使用第二个寄存器来完成,通常称为帧指针。一个函数通常在一开始就做这样的事情

PUSH  FP       ; Save the old Frame Point 
MOV   SP  FP   ; Save the stack pointer
SUB   BYTESNEEDED, SP

函数最后会做类似的事情

MOV FP, SP ;释放函数分配的所有堆栈 POP FP ;恢复旧的堆栈指针

使用两个寄存器的原因是可以从堆栈中动态分配数据。

有一个名为 alloca 的通用函数(虽然我相信它不是标准的 C 函数),它是 malloc 的替代方法,从堆栈中分配

void dosomething (int amount)
{
    char *data = alloca (amount) ;
} 

使用alloca,当函数返回并重置堆栈时,数据会自动释放。

这是对您问题的冗长回答。是的,当声明一个字符时,必须对其进行分配。但是,此分配是在幕后完成的,您无需付出任何努力。

【讨论】:

    猜你喜欢
    • 2016-04-29
    • 2013-01-06
    • 2015-12-24
    • 1970-01-01
    • 2011-02-17
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 1970-01-01
    相关资源
    最近更新 更多