【问题标题】:is this object on stack or heap?这个对象是在堆栈还是堆上?
【发布时间】:2016-12-27 10:47:01
【问题描述】:

在 C++/CLI 中,以下两个是相同还是不同?

System::String ^source("Hello World");

System::String ^source= gcnew System::String("Hello World");

第一个在堆栈上,第二个在堆上吗?
还是它们都在堆上?
.Net 对象我相信只有引用,它们不能像 C++ 允许的那样在堆栈上创建。谁能解释一下?

【问题讨论】:

  • .NET 同时具有堆和堆栈类型。
  • @Matteo:C++/CLI 不是 C++,你知道吗?
  • @Deduplicator:C++/CLI 是 C++ 的超集,它允许将标准 C++ 与托管内容混合。考虑到(例如)许多在 C++/CLI 方面有一定经验的人(比如我)确实遵循 C++ 标签而不是 C++/CLI,我认为同时使用这两个标签并没有什么坏处。痴迷地删除 C++ 标签以寻找纯度 IMO 只是幼稚。
  • @MatteoItalia:C++/CLI 充其量是基于 C++。相比之下,托管 C++ 尝试(或成功?)成为超集,但最终失败了。无论如何,如果您对这两个标签都感兴趣,欢迎您关注这两个标签。

标签: .net c++-cli heap-memory


【解决方案1】:

字符串既不存储在堆栈中,也不存储在堆中。故事有点绕。

考虑它的通常有用的方法是引用类型对象总是存储在 GC 堆上。与 C++(又名 std::string)非常相似,像字符串这样的可变长度对象需要使用空闲存储来分配正确的内存量。对 std::string 中的一个可能的微优化取模,它可以在 std::string 对象中存储非常短的字符串。但通常 std::string 对象本身可以在堆栈上分配,而字符串 content 在堆上分配。就像source 在堆栈上一样,只是垃圾收集器可以找到的普通指针。

C 语言允许将字符串内容存储在堆栈中,但您必须预先猜测所需的字符串缓冲区长度。启动数以千计的恶意软件攻击,字符串缓冲区溢出是扰乱程序堆栈帧并改变函数返回值的标准技术。不是 .NET 方式。 C 语言编译器没有必须这样做,他们只是非常普遍地这样做。

但在您给出的示例中并不直截了当。语句之间没有区别,字符串内容既不在堆栈上,也不在堆上。 CLR 进行了大量的微优化,以利用 CLI 规范,该标准描述了字符串在符合 CLR 实现中必须如何表现。

它利用了字符串对象不可变的特性。这允许称为 interning 的优化。字符串对象的外观和行为就像它存储在 GC 堆上一样。但实际上并非如此,对象内容是直接从程序集的内存映射图像中读取的。存储在程序集元数据的“blob 堆”中。 GC 在收集时遇到这样的字符串对象时会忽略它们。非常类似于字符串文字在 C 语言中的行为方式。减去导致十亿次崩溃的错误(字符串文字是 char* 而不是应该的 const char*),由于不变性保证,您永远不会意外写入字符串文字。

【讨论】:

  • “它利用了字符串对象不可变的特性。这允许一种称为实习的优化。”还有第二个前提条件,即相等的字符串可能总是相同的。这不是强制性的,至少在程序集之间不是强制性的,对吧?不错的帖子。
  • 无法保证相同的字符串具有相同的对象地址。 CLR 不会消耗任何循环来尝试查找可以匹配单个实习字符串的字符串,这是在编译时进行排序的。像 String.Empty 这样的规范字符串文字是 readonly 而不是 const 的基本原因。
  • 如果您认为 System::String 是 CLR 中实例没有预定大小的两种类型之一,那么故事会变得更加复杂。
猜你喜欢
  • 2011-02-03
  • 2010-11-06
  • 1970-01-01
  • 2021-06-19
  • 2013-12-09
  • 2011-04-08
  • 1970-01-01
  • 1970-01-01
  • 2013-10-26
相关资源
最近更新 更多