我们的项目中有一些严格类型的整数类型:
struct FooIdentifier {
int raw_id; // the only data member
// ... more shenanigans, but it stays a "trivial" type.
};
struct BarIdentifier {
int raw_id; // the only data member
// ... more shenanigans, but it stays a "trivial" type.
};
Run Code Online (Sandbox Code Playgroud)
基本上是这里提出的或类似于Unit Library 中使用的东西。
除了类型系统之外,这些结构基本上都是整数。
我的问题在这里现在是:有没有C ++语言保证这些类型奠定了相当于100%的内存作为一个经常int会是什么?
注意:由于我可以静态检查类型是否具有相同的大小(即没有填充),我真的只对无意外填充的情况感兴趣。我应该从一开始就添加这个注释
// Precodition. If platform would yield false here, I'm not interested in the result.
static_assert(sizeof(int) == sizeof(ID_t)); …Run Code Online (Sandbox Code Playgroud) 鉴于此代码:
#include <iostream>
struct A {
};
struct B {
};
struct C {
};
struct E : A {
int field;
};
struct F : A, B {
int field;
};
struct G : A, B, C {
int field;
};
int main() {
std::cout << _MSC_VER << std::endl;
std::cout << sizeof(E) << std::endl;
std::cout << sizeof(F) << std::endl;
std::cout << sizeof(G) << std::endl;
int o;
std::cin >> o;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到以下输出:
1900
4
8
8
Run Code Online (Sandbox Code Playgroud)
为什么会F …
基本上,如果我有
typedef struct {
int x;
int y;
} A;
typedef struct {
int h;
int k;
} B;
Run Code Online (Sandbox Code Playgroud)
我有A a,C标准保证((B*)&a)->k是否相同a.y?
来自C/C++的背景,关于减少缓存未命中的对象的内存布局是特别在处理控制台时尤其重要的.面向数据的设计通常比面向对象的设计更受青睐,以帮助保持相关对象在内存中彼此靠近(特别是在性能关键区域).
最近,我一直在做一些Javascript开发,我想知道Javascript社区中普遍的共识是什么.
由于我在Javascript方面的经验有限,我经常惊讶于在分析时看到完全出乎意料的结果.从浏览器到浏览器,Javascript对象/结构的内部存储器布局和实现变化很大,我想知道是否值得尝试优化.
我在jsPerf上创建了一个简单的测试用例(http://jsperf.com/object-vs-data)来比较这两种方法的性能,虽然它显示了Chrome的性能提升,但是Safari没有明显的加速.
在Javascript中,我是否应该关注对象的内存布局?或者它更像是"以一种方式实施,然后根据需要进行优化"类型的东西?
第二种选择似乎是浪费(就开发时间而言),特别是如果有一些好的指导方针可以遵循.
谢谢〜
补充信息:这基本上是我如何在Javascript中实现这两种方法.上面的jsPerf测试用例就是这样实现的.
var objectOriented = [
{ foo: 1, bar: 2 },
{ foo: 3, bar: 4 }
];
var dataOriented = {
foos: [1, 3],
bars: [2, 4]
};
// Object-oriented access:
var a = objectOriented[0].bar;
// Data-oriented access:
var b = dataOriented.bars[0];
Run Code Online (Sandbox Code Playgroud) 这可能是一个重复的问题.我想知道windows进程的内存映射是什么样的?我正在寻找细节.请提供博客,文章和其他相关文献的链接.
警告:这仅仅是那些热衷于破解东西以理解其力学的人的练习.
我正在探索我在C#中可以实现的极限,并且我编写了一个ForceCast()函数来执行一个没有任何类型检查的强力转换.切勿考虑在生产代码中使用此功能.
我写了一个名为call的类Original和一个名为struct的结构LikeOriginal,两个都有两个整数变量.在Main()我创建了一个名为新变量orig,并将其设置为一个新的实例Original与a=7和b=20.何时orig被转换LikeOriginal并存储casted,其值cG和dG未定义,这LikeOriginal是一个结构和类实例包含比结构实例更多的元数据,因此导致内存布局不匹配.
示例输出:
Casted Original to LikeOriginal
1300246376, 542
1300246376, 542
added 3
Casted LikeOriginal back to Original
1300246379, 545
Run Code Online (Sandbox Code Playgroud)
但是请注意,当我打电话casted.Add(3),并转换回Original并打印的价值a和b,令人惊讶的是,他们成功地通过3递增,而这一直是重复的.
让我感到困惑的是,将类强制转换为struct将导致cG并dG映射到类元数据,但是当它们被修改并强制转换为类时,它们会正确映射到a和b.
为什么会这样?
使用的代码:
using System;
using System.Runtime.InteropServices;
namespace BreakingStuff {
public class Original …Run Code Online (Sandbox Code Playgroud) 空基优化很棒。但是,它具有以下限制:
如果空基类之一也是第一个非静态数据成员的类型或类型的基类,则禁止空基类优化,因为相同类型的两个基子对象在对象表示中需要具有不同的地址派生最多的类型。
要解释此限制,请考虑以下代码。该static_assert会失败。而更改Foo或Bar改为继承自Base2将避免错误:
#include <cstddef>
struct Base {};
struct Base2 {};
struct Foo : Base {};
struct Bar : Base {
Foo foo;
};
static_assert(offsetof(Bar,foo)==0,"Error!");
Run Code Online (Sandbox Code Playgroud)
我完全理解这种行为。我不明白的是为什么存在这种特殊行为。很明显,添加它是有原因的,因为它是一个明确的添加,而不是一个疏忽。这样做的理由是什么?
特别是,为什么要要求两个基础子对象具有不同的地址?在上面,Bar是一个类型并且foo是该类型的成员变量。我不明白为什么基类对Bar类型的基类很重要,foo反之亦然。
事实上,如果有的话,我希望它&foo与Bar包含它的实例的地址相同——因为它需要在其他情况下(1)。毕竟,我对virtual继承并没有做任何花哨的事情,无论如何基类都是空的,并且编译Base2显示在这种特殊情况下没有任何问题。
但显然这种推理在某种程度上是不正确的,并且在其他情况下需要这种限制。
假设答案应该是针对 C++11 或更新版本的(我目前使用的是 C++17)。
(1)注意:EBO 在 C++11 中得到了升级,特别是对于StandardLayoutTypes 来说是强制性的(尽管Bar上面的 不是StandardLayoutType)。
考虑以下层次结构
struct A {
int a;
A() { f(0); }
A(int i) { f(i); }
virtual void f(int i) { cout << i; }
};
struct B1 : virtual A {
int b1;
B1(int i) : A(i) { f(i); }
virtual void f(int i) { cout << i+10; }
};
struct B2 : virtual A {
int b2;
B2(int i) : A(i) { f(i); }
virtual void f(int i) { cout << i+20; }
};
struct C : B1, virtual …Run Code Online (Sandbox Code Playgroud) c++ multiple-inheritance virtual-inheritance vtable memory-layout
我对程序在内存中的样子有点困惑,我的教授告诉我堆栈和堆在堆栈处于较低的内存地址时相互增长.
使用该映像困扰我的第一件事是,如果堆从高到低增长,那么如果我在堆上分配了一个数组,那么第二个元素的指针在int值中是否应该小于指向第一个元素的指针?这会令人困惑
我做了一点研究,我发现了这个数字(注意我的问题集中在linux上)
布局http://www.cyberplusindia.com/blog/wp-content/uploads/2008/10/memorysegment.gif
好吧,所以数据和未初始化的数据位于文本段之后,位于程序内存的开头,然后是堆后跟堆栈,最后是命令行参数和环境.
但是如果堆栈从高地址变为低,那么如果我在堆栈上分配了一个数组,那么如果我指向第一个元素的指针的值也会低于指向第二个元素的指针?这是不是意味着堆栈也会从低到高增长?
所以我的问题是Linux中进程的正确内存布局是什么?以及共享库的内存来自何处(在进程的地址空间中)
带指针示例的简单代码:
#include <iostream>
int data[5];
int main()
{
using std::cout;
using std::endl;
int stack = 0;
short *sptr = reinterpret_cast<short *> ( &stack );
int *iptr = new int[5];
cout << "Starting static tests"
<< "\nPointer to first element " << data
<< "\nPointer to second element " << &data[1]
<< "\nstarting stack test " << sptr
<< "\nsecond short " << &sptr[1]
<< "\nStarting heap test " << iptr
<< "\nsecond int …Run Code Online (Sandbox Code Playgroud) 有没有办法使用g ++编译器或任何其他方法打印C++对象的布局.一个简化的例子(假设int需要4个字节)
class A{
int a;
};
class B:public A{
int b;
}
Run Code Online (Sandbox Code Playgroud)
所以输出就是
A-
0 4
+ a +
B-
0 4 8
+ A.a + b +
Run Code Online (Sandbox Code Playgroud)
理解对象的布局(在我的例子中是虚拟机代码)会很有用.
提前致谢.
问候,扎赫尔
memory-layout ×10
c++ ×6
casting ×2
class ×2
struct ×2
c ×1
c# ×1
g++ ×1
inheritance ×1
javascript ×1
linux ×1
low-level ×1
oop ×1
vtable ×1
windows ×1