我已经搜查,但是我不理解很好这三个概念。当我们使用的动态分配(堆中)什么是其真正的优势?什么是问题的静态和栈?我可以写一个整个应用而不分配变量的堆?

我听说其他语言并入一个"垃圾",所以你不必担心存储器。这是什么垃圾回收做什么?

你可以做什么操纵的记忆你自己,你不能这样做使用这个垃圾?

一旦有人对我说这与本宣言:

int * asafe=new int;

我有一个"指向一个指".这是什么意思?这是不同的:

asafe=new int;

?

有帮助吗?

解决方案

一个类似的问题 有人问,但它没有要求约静。

摘要什么样的静态、堆堆存是:

  • 一个静态的变基本上是一个全球性可变的,甚至如果你不能访问它在全球范围。通常有一个地址用于它,是在可执行的本身。只有一个复制的整个程序。无论多少次你进入一个函数呼吁(或类)(以及在有多少线!) 变量是指相同的存储位置。

  • 堆一堆的存储器可以使用的动态。如果你想4kb为一个对象然后动态的分配将会看起来通过其清单的免费空间堆中,挑选出一个4kb块,并把它交给你。通常,动态存储器(malloc,新et c.) 开始结束时的记忆和工作的倒退。

  • 说明如何堆的增长和缩小一点的范围之外这个答案,但我只想说你总是添加和去除从端只。堆通常开始高和增长下降到低的地址。你跑出来的记忆当堆满足动态的分配在中间的某个地方(但是参照物理与虚拟存储器和碎片).多线程将需要多个堆栈(的过程一般储备金的最小尺寸的stack)。

当你想要利用每一个:

  • 静/globals是有用的存储器,你知道,你总是需要你知道你曾经不想要释放.(通过的方式、嵌入式的环境中可能被认为只具有静态存储器...堆堆的组成部分的已知的地址空间共享通过的第三个存储器类型:该程序的代码。计划将经常做的动态分配了他们的静态存储器的时候他们需要的东西像链接清单。但无论如何,静态存储器本身(缓冲区)本身不是"分配",而是其他目的分配出去的记忆举行的通过的缓冲区用于这一目的。你可以做这种非嵌入,以及和控制台游戏,经常避免的内在动态存储器的机制,有利于紧紧地控制分配过程中通过使用缓冲区的预设的大小的所有拨款。)

  • 堆变量是有用的,当你知道,只要功能是在范围(在叠的地方),你会想变量为依然存在。堆不错的变量,你需要代他们位于何处,但它不是需要之外,代码。他们也真的很好因为当你访问的资源,如文件,并要的资源,以自动走开当你离开这个代码。

  • 堆分配(动态分配的存储器)是有用的,当你想要更多的灵活于以上。通常,一个功能被称为回应的一个事件(使用者点击"创建箱"按钮)。适当的响应可能需要分配新的对象(一个新的框物),应该坚持长期功能后退出,因此它不可能是在堆。但你不知道有多少盒子你会希望在开始的程序,所以它不可能是一个静态的。

垃圾收集

我已经听说了很多最近关于如何伟大的垃圾收集,因此,也许一点持反对意见的声音将是有益的。

垃圾收集是一个美妙的机制为时表现不是一个巨大的问题。我听到Gc得更好和更复杂的,但事实是,你可能会被迫接受的性能损失(这取决于使用的情况下)。如果你懒,它仍然可能无法正常工作。在最好的时代,垃圾收藏家认识到,你的记忆消失的时候,它意识到,没有更多的参考(见 参考计数).但是,如果你有一个对象,是指本身(可能通过参照另一个目的,它指的是回来的),然后参考计数不会单独表明,存储器可以删除。在这种情况下,GC需要看看整个参考汤并找出是否有任何群岛,都只提到通过自己。随便的,我想这是一个O(n^2)操作的,但不管它是什么,它可以得到不好的如果你在所有有关的性能。(编辑:马丁B 点了 这是O(n)对于合理有效率的算法。这仍然是O(n)太多了如果你是有关绩效和可以释放在固定的时间没有垃圾收集。)

就个人而言,当我听到有人说,C++没有垃圾收集,我心中的标签,作为一个特征C++,但是我可能是在少数民族。可能是最难的事情对人们了解关于编程在C和C++是指针以及如何正确处理他们的动态存储器的拨款。一些其他语言,如蟒蛇,将是可怕的,而不GC,所以我认为这归结为什么你想出来的一种语言。如果你想要可靠的业绩,那么C++没有垃圾收集是唯一的东西这一边的Fortran我能想到的。如果你想要的便于使用和训练车轮(拯救你崩溃,而不需要你了解的"适当的"存储管理),挑选一些与GC。甚至如果你知道如何管理忆及,它将节省你的时间你可以花优化的其他代码。真的没有太多的性能损失了,但是如果你真的需要可靠性(和能力知道究竟是怎么回事的时候,下面)然后我会坚持C++。还有一个原因是,每一个主要引擎,我已经听过的是用C++(如果不是C或组件)。Python,et al细编写脚本,但不是游戏的主要引擎。

其他提示

以下当然都不太准确。读它时带上一粒盐:)

嗯,你提到的三件事是自动,静态和动态存储持续时间,这与对象的生存时间和生命开始时间有关。


自动存储时间

您使用短期小型数据的自动存储持续时间,在某些块中仅需本地

if(some condition) {
    int a[3]; // array a has automatic storage duration
    fill_it(a);
    print_it(a);
}

一旦我们退出块,生命周期就会结束,并且一旦定义了对象就会立即开始。它们是最简单的存储持续时间,并且比特定的动态存储持续时间更快。


静态存储时间

对自由变量使用静态存储持续时间,任何代码都可以访问它们,如果它们的范围允许这样的使用(命名空间范围),以及需要在其范围退出时延长其生命周期的局部变量(本地范围) ),以及需要由其类的所有对象(类范围)共享的成员变量。它们的生命周期取决于它们所处的范围。它们可以具有命名空间范围本地范围类范围。这两者的真实之处在于,一旦生命开始,生命终止于程序结束。以下是两个例子:

// static storage duration. in global namespace scope
string globalA; 
int main() {
    foo();
    foo();
}

void foo() {
    // static storage duration. in local scope
    static string localA;
    localA += "ab"
    cout << localA;
}

程序打印 ababab ,因为 localA 在退出其块时不会被销毁。您可以说当控件达到其定义时,具有局部范围的对象开始生命周期 。对于 localA ,它会在输入函数体时发生。对于命名空间范围内的对象,生命周期从程序启动开始。对于类范围的静态对象也是如此:

class A {
    static string classScopeA;
};

string A::classScopeA;

A a, b; &a.classScopeA == &b.classScopeA == &A::classScopeA;

如您所见, classScopeA 未绑定到其类的特定对象,而是绑定到类本身。上面所有三个名称的地址是相同的,都表示相同的对象。有关静态对象何时以及如何初始化的特殊规则,但现在不要关注它。这意味着术语静态初始化顺序惨败


动态存储时间

最后一个存储时间是动态的。如果你想让对象在另一个岛上生存,你想使用它,并且你想要引用它们引用它们。如果您的对象,并且您想要创建仅在运行时中已知的大小数组,也可以使用它们。由于这种灵活性,具有动态存储持续时间的对象复杂且管理缓慢。具有该动态持续时间的对象在适当的 new 运算符调用发生时开始生命周期:

int main() {
    // the object that s points to has dynamic storage 
    // duration
    string *s = new string;
    // pass a pointer pointing to the object around. 
    // the object itself isn't touched
    foo(s);
    delete s;
}

void foo(string *s) {
    cout << s->size();
}

只有当您为它们调用 delete 时,它的生命周期才会结束。如果你忘记了,那些对象永远不会终结。定义用户声明的构造函数的类对象不会调用其析构函数。具有动态存储持续时间的对象需要手动处理其寿命和相关的存储器资源。存在库以便于使用它们。 特定对象显式垃圾回收可以使用智能指针建立:

int main() {
    shared_ptr<string> s(new string);
    foo(s);
}

void foo(shared_ptr<string> s) {
    cout << s->size();
}

您不必关心调用delete:如果引用该对象的最后一个指针超出范围,则共享ptr会为您执行此操作。共享ptr本身具有自动存储持续时间。因此生命周期是自动管理的,允许它检查是否应该在其析构函数中删除指向动态对象的内容。有关shared_ptr参考,请参阅增强文档: http://www.boost .ORG / DOC /库/ 1_37_0 /库/ smart_ptr / shared_p

它已经说过精心,只是作为"简短的回答":

  • 静态变量(分类)
    寿命=程序的运行(1)
    能见度=确定通过访问剂(私人/保护/公开的)

  • 静态变量(全球范围)
    寿命=程序的运行(1)
    能见度=汇编单位的实例(2)

  • 堆变
    寿命=由你定义(新删除)
    能见度=由你定义(不管分配的指针)

  • 堆变
    能见度=从《宣言》直到范围退出
    寿命=从《宣言》一直到宣布范围是退出


(1)更确切地说:从初始化,直到取消初始化的汇编单元(即C/C++文件)。顺序初始化的汇编单位没有定义的标准。

(2)要注意:如果你化静态变量在一个标题,每个编译单元都有自己的副本。

我确信其中一位学生很快会得到一个更好的答案,但主要区别在于速度和体型。

堆栈

分配速度更快。它在O(1)中完成,因为它是在设置堆栈帧时分配的,因此它基本上是免费的。缺点是,如果你的堆栈空间不足,你就会被剔除。你可以调整堆栈大小,但IIRC你可以玩大约2MB。此外,一旦退出该功能,堆栈上的所有内容都将被清除。因此,稍后引用它可能会有问题。 (指向堆叠已分配对象的指针会导致错误。)

分配速度极慢。但你有GB可以玩,并指向。

垃圾收集器

垃圾收集器是一些在后台运行并释放内存的代码。当你在堆上分配内存时,很容易忘记释放它,这被称为内存泄漏。随着时间的推移,应用程序消耗的内存会增长并增长,直到崩溃为止。让垃圾收集器定期释放你不再需要的内存有助于消除这类错误。当然,这需要付出代价,因为垃圾收集器会降低速度。

什么是问题的静态和栈?

这个问题与"静态"分配,分配是在编写的时间:你不能用它来分配某些变量数据的数量,其数量是不知道直到运行时间。

该问题与分配上"堆"是分配的销毁,尽快子程序而不分配返回。

我可以写一个整个应用而不分配变量的堆?

也许但不是一个不平凡、正常的,大应用程序(但是所谓的"嵌入"程序可能会写不堆使用的一个子集C++)。

什么样的垃圾?

它一直在看你的数据("标志和扫荡"),以检测时应用程序不再引用。这便于应用,因为该程序并不需要分配的数据...但是,垃圾收集器可以计算价格昂贵。

垃圾回收不是一个通常特征的C++编程。

你可以做什么操纵的记忆你自己,你不能这样做使用这个垃圾?

学习C++的机制确定性的存释:

  • '静止':永远不会被释放
  • '堆':尽快变"的范围"
  • '堆':时的指针是删除(明确删除的申请,或隐含地删除的内的一些或其他的子程序)
当堆栈过于“深”时,堆栈内存分配(函数变量,局部变量)可能会出现问题。并且溢出了可用于堆栈分配的内存。堆用于需要从多个线程或整个程序生命周期中访问的对象。您可以在不使用堆的情况下编写整个程序。

如果没有垃圾收集器,您可以非常轻松地泄漏内存,但您也可以指定何时释放对象和内存。我在运行GC时遇到了Java问题并且我有一个实时进程,因为GC是一个独占线程(没有别的东西可以运行)。因此,如果性能至关重要并且您可以保证没有泄漏的对象,则不使用GC非常有帮助。否则,当你的应用程序消耗内存并且你必须追踪泄漏源时,它只会让你讨厌生命。

如果您的程序不知道要分配多少内存(因此您不能使用堆栈变量),该怎么办?说链接列表,列表可以增长,而不知道它的大小是什么。因此,当您不知道将多少元素插入其中时,在堆上进行分配对于链表是有意义的。

在某些情况下GC的一个优点是其他人的烦恼;对GC的依赖鼓励人们不要多考虑它。理论上,等到“空闲”期间或直到绝对必须,它会窃取带宽并导致应用程序中的响应延迟。

但你不必“不考虑它”。就像多线程应用程序中的其他所有内容一样,当您可以屈服时,您可以屈服。例如,在.Net中,可以请求GC;通过这样做,而不是更频繁地运行GC,可以更频繁地缩短运行GC,并分散与此开销相关的延迟。

但是这打败了GC的主要吸引力,似乎“被鼓励不必多思考它,因为它是自动化的。”

如果您在GC变得普遍并且对malloc / free和new / delete感到满意之前第一次接触到编程,那么甚至可能会发现GC有点烦人和/或不信任(因为可能是不信任'优化',这已经有一段曲折的历史。)许多应用程序容忍随机延迟。但对于没有随机延迟不太可接受的应用程序,常见的反应是避开GC环境并向纯粹的非托管代码(或上帝禁止,长期垂死的艺术,汇编语言)方向移动。

我有一个暑假学生,一个实习生,聪明的孩子,他在GC上断奶;他非常喜欢GC的优势,即使在非托管C / C ++编程时他拒绝遵循malloc / free new / delete模型,因为引用“你不应该用现代编程语言来做这件事。 &QUOT;而且你知道?对于小型,短期运行的应用程序,您确实可以逃脱,但不适用于长期运行的高性能应用程序。

堆栈是由编译器分配的内存,当我们编译程序时,默认编译器从OS分配一些内存(我们可以从IDE中的编译器设置更改设置)而OS是给你内存的那个,它取决于系统上的许多可用内存和许多其他东西,并且当我们声明它们复制的变量(ref as formals)时,将分配到堆栈内存,这些变量被推送到堆栈它们遵循一些命名约定默认情况下它的CDECL在Visual工作室 中文:中缀符号: C = A + B; 堆栈推送从右到左推送,b到堆栈,操作员,堆栈和那些i的结果,即堆叠。 在预修补符号中: = +驾驶室 这里所有变量都被推到第一个堆栈(从右到左),然后进行操作。  编译器分配的内存是固定的。因此,假设我们的应用程序分配了1MB的内存,假设变量使用了700kb的内存(除非动态分配,否则所有局部变量都被推送到堆栈中),因此剩余的324kb内存被分配给堆。 并且这个堆栈的生命周期较短,当函数的范围结束时,这些堆栈被清除。

scroll top