我希望您认识到所有这些都是针对Java和C ++的深层实现定义的。话虽如此,Java的对象模型需要大量空间。
C ++对象通常不需要成员所需要的任何存储。请注意(与Java不同,在Java中,用户定义的所有内容都是引用类型),客户端代码可以将对象用作值类型或引用类型,即,一个对象可以存储指向另一个对象的指针/引用,或者直接存储该对象没有间接。如果有任何virtual
方法,则每个对象都需要一个额外的指针,但是很多有用的类被设计为无需多态性就可以相处并且不需要这样做。没有GC元数据,也没有每个对象的锁定。因此,class IntWrapper { int x; public: IntWrapper(int); ... };
对象不需要的空间比plain所需的空间更多int
,并且可以直接(即无间接)放置在集合和其他对象中。
数组之所以棘手,仅仅是因为没有与C ++中的Java Array通用的预制组件。您可以简单地分配一堆对象new[]
(绝对没有开销/元数据),但是没有长度字段-实现可能存储了一个对象,但您无法访问它。std::vector
是一个动态数组,因此具有额外的开销和更大的接口。std::array
和C样式的数组(int arr[N];
),需要一个编译时常量。从理论上讲,它应该只是对象的存储空间,再加上一个长度的整数-但是由于可以动态调整大小和功能齐全的接口而几乎没有多余的空间,因此在实践中就可以做到这一点。请注意,所有这些集合以及所有其他集合,默认情况下都是按值存储对象,从而节省了间接寻址和引用空间,并改善了缓存行为。您必须显式存储指针(请使用智能指针)以进行间接访问。
上面的比较并不完全公平,因为其中一些节省是由于不包括Java包含的功能而获得的,并且它们的C ++等效项通常没有Java等效项(*)更好。virtual
用C ++ 实现的通用方法所产生的开销与virtual
用Java 实现的通用方法一样多。要获得锁,您需要一个功能齐全的互斥对象,该对象很可能大于几位。获取参考计数(不是等效于GC,因此不应使用,但有时很有用),您需要一个智能指针,该指针会添加一个引用计数字段。除非精心构造对象,否则引用计数,智能指针对象和引用对象位于完全独立的位置,即使正确构造它,共享指针也可能(必须?)仍然是两个指针而不是一个。再说一次,良好的C ++样式使用这些功能不足以解决问题-实际上,编写良好的C ++库的对象使用较少。这不一定意味着总体上减少了内存使用量,但确实意味着C ++在这方面具有良好的领先优势。
(*)例如,通过将类型信息与各种标志合并,并删除对象的锁定位,可以获得虚拟调用,身份哈希码和某些对象仅使用一个单词(许多其他对象使用两个单词)锁定不太可能需要锁。有关此优化和其他优化的详细说明,请参见David F. Bacon,Stephen J. Fink和David Grove 的Java对象模型的节省空间和时间的实现(PDF)。
int
?如果是这样,您应该将其与int
Java中的进行比较,Integer
只要C ++ int是32位,就不应该进行比较。