将应用程序从32位升级到64位会增加指针大小和对象的内存占用量.
我正在寻找尽可能减少对象内存占用的方法.对于POD结构,我转储结构的内存布局,以找出如何打包成员并减少编译器填充.
有没有办法找出非POD对象的内存布局,如类实例?我怎么能实现类包装类对象的东西?
谢谢,丹
如果动态行向末端移动,则获取数据的速度之间是否存在任何差异.
例如:int,int,int,text是否比int int text int好?
我的领导告诉我这个事实,从互联网上怎么没有这样的信息?请帮忙 ?
由于我之前的问题没有成功(" 使用x86/x64 C API的C#AnyCPU库 - 打包结构,调用和回调 "),我将编写一个更简洁和抽象的问题.
图片:
我工作的公司有一个64位移植的软件.该软件包含一个BASE库(带有C API的C++)和C API上的两个包装器:一个C++包装器和一个.NET包装器.
C++ BASE库和C++ WRAPPER应该具有x86/x64构建配置..NET WRAPPER应该只有AnyCPU构建配置.
从.NET WRAPPER中选择正确的库已经成功完成(两个C++ BASE库(x86/x64)都被加载到两个独立的命名空间中,并且根据IntPtr的大小,在运行时调用正确的函数;这不一定需要两个库都在那里,但只有一个被使用).
问题:
BASE库中的所有结构都以4个字节对齐:
#pragma pack(push,4)
Run Code Online (Sandbox Code Playgroud)
为了让代码在64位上没有警告编译,我添加了选择性对齐(C++ BASE和C++ WRAPPER工作,如魅力):
#ifdef WIN64
#pragma pack(push,8)
#else
#pragma pack(push,4)
#endif
Run Code Online (Sandbox Code Playgroud)
问题与.NET中的结构有关:
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
internal struct DBConnectionSettings{...}
Run Code Online (Sandbox Code Playgroud)
由于AnyCPU是唯一需要的WRAPPER配置,因此该结构不能具有选择性打包.
在不同的.NET命名空间中创建在8个字节上对齐的单独结构是非常困难的(很多和很多的PEFRORMANCE LOSS)...... 然而,这可能是我们可能完全正常工作的唯一解决方案.
回归到x86和x64的4字节对齐问题很多警告,因为100%的结构对打包敏感,特别是对于一元运算符(问题仅出现在x64解决方案配置上,对齐4字节).很多崩溃,除非我们添加虚拟成员,否则结构无法对齐.我应该提一下,结构是基于含义或与许可证/目标OS(ifdefs)相关的分组.为所有可能性添加填充(虚拟)成员需要数月.
将8个字节上的所有内容对齐都不是解决方案,因为我们再次崩溃整个地方 - 仅对于x86,x64工作得很好 - 结构对齐需要再次使用虚拟(填充)成员并根据大小进行分组.
结论(问题):
1)对于x86和x64解决方案配置,C++代码是否可以对齐4?如何实现这一目标?
2)x86和x64对齐的最佳替代方案是什么?指针大小肯定应该统一对齐(在我看来).我们正在寻求拥有FAST软件,不一定具有内存效率(到目前为止,x86系统上的内存指纹介于15mb和2gb之间).
3)对于.NET和C之间的互操作,带有函数指针的结构有什么特殊需求?
4)高度赞赏任何建议的替代方案.
我们一直在这个互联网上搜索一个多月(我们星球上的那个),但我们无处可去.一些建筑师恳求使用选择性打包(4/8),而有些人认为软件不是直截了当的,应该重构.这不是我的决定该做什么,但我可以提出有充分理由的想法.该软件已于2000年末启动,当时STL出现故障,因此BASE有自己的容器,专门针对上帝知道什么.我不应该在这里表达我的意见,因为它不是基督徒.
我注意到std :: pair在尝试将其保存到二进制文件时发生了一件令人不愉快的事情:std :: pair与一个单词对齐.它在处理器效率方面可能很有用,但需要更多的存储空间,所以我想将对齐模式切换为1字节的std :: pair.我的编译器是MS VC++ 2012.
#include <iostream>
int main( )
{
struct S_a { double a; size_t b; };
#pragma pack(1)
struct S_wa { double a; size_t b; };
std::cout << sizeof( size_t ) << '\n'; // 4
std::cout << sizeof( double ) << '\n'; // 8
std::cout << sizeof( std::pair< size_t, size_t > ) << '\n'; // 8
std::cout << sizeof( std::pair< double, size_t > ) << '\n'; // 16 - bad
std::cout << sizeof( …Run Code Online (Sandbox Code Playgroud) 我知道将Eigen类型与动态内存结合使用时会出现对齐问题。因此,我决定Eigen::DontAlign 根据此页面禁用向量化,但是以下代码仍在执行时一致地引发SIGSEGV。如果有人可以阐明为什么会发生,我会很高兴。从我的角度来看,使用Eigen::DontAlign应该使我摆脱了对齐的复杂性。
#include <Eigen/Dense>
#include <vector>
int main()
{
using vec_t = Eigen::Matrix< double, 4, 1, Eigen::DontAlign >;
std::vector< vec_t > foo;
foo.emplace_back( 0.0, 0.0, 0.0, 1.0 );
vec_t vec{ -4.0, 1.0, 3.0, 1.0 };
foo.push_back( vec );
}
Run Code Online (Sandbox Code Playgroud)
GDB输出:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000408bed in Eigen::internal::evaluator<Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 2, 4, 1> > >::packet<0, double __vector(4)>(long long, long long) const (this=0x22fa90, row=0, col=0)
at C:/Dev/Eigen/Eigen/src/Core/CoreEvaluators.h:197
197 return ploadt<PacketType, LoadMode>(m_data + row + col * …Run Code Online (Sandbox Code Playgroud) 我有以下内容:
#include <stdio.h>
typedef union u_data
{
struct
{
int a;
int b;
int c;
};
int elem[3];
} my_data;
int main(void)
{
my_data data;
data.a = 3;
data.b = 5;
data.c = -3;
printf("%d, %d, %d\n", data.elem[0], data.elem[1], data.elem[2]);
}
Run Code Online (Sandbox Code Playgroud)
它按照我的预期输出:3, 5, -3
但是我知道结构中可以有填充,所以这是否意味着结构中的元素可能并不总是与数组对齐?
说我有一个这样的工会
union blah {
foo f;
bar b;
};
Run Code Online (Sandbox Code Playgroud)
其中 和foo都是bar可简单复制的。这样做安全吗:
blah b;
foo f;
memcpy(&b, &f, sizeof(f));
Run Code Online (Sandbox Code Playgroud)
然后b.f作为活跃的工会成员使用?或者,我是否必须 memcpy 到特定的工会成员,如下所示:
memcpy(&b.f, &f, sizeof(f));
Run Code Online (Sandbox Code Playgroud)
我在实践中担心这一点的原因是因为我将不得不编写一个大致如下的函数:
template<int c>
void init_union(blah& b, typename type_family<c>::type const& t) {
switch (c) {
case 0:
memcpy(&b.p0, &t, sizeof(t));
break;
case 1:
memcpy(&b.p1, &t, sizeof(t));
break;
// etc.
}
}
Run Code Online (Sandbox Code Playgroud)
但我宁愿能够跳过整个 switch 语句并只写这个:
template<int c>
void init_union(blah& b, typename type_family<c>::type const& t) {
memcpy(&b, &t, sizeof(t));
}
Run Code Online (Sandbox Code Playgroud) 最近我观察到,在 Clang 9.0 上,alignof和__alignof返回unsigned long long的不同值,并且在https://reviews.llvm.org/D54814上也讨论了同样的问题:
从 Clang 8.0 和 GCC 8.0 开始,在相同情况下返回不同的值
alignof。__alignof具体而言alignof,and_Alignof返回类型的最小对齐方式,其中 as__alignof返回首选对齐方式。
我了解类型对齐,但从未遇到过“最小对齐”和“首选对齐”。
有人可以帮我理解这些到底是什么以及有什么区别吗?谢谢。
我正在学习结构填充,并了解到结构填充背后的原因是,如果结构的成员未对齐,处理器将无法仅在一个周期内读取/写入它们。一般来说,由N字节组成的数据类型的位置应该是 的倍数的地址N。
假设这个结构体例如:
struct X
{
char c;
// 3 bytes padding here so that i is aligned.
int i;
};
Run Code Online (Sandbox Code Playgroud)
这里这个结构体的大小应该是8个字节,c默认是对齐的,因为它只占用1个字节,但i事实并非如此。对于i,我们需要在其前面添加 3 个字节的填充,使其“对齐”并且只能在一个周期内访问。告诉我我是否遗漏了什么。
1 - 对齐是如何工作的?成员们的立场是什么?
2 - 对于 CPU 访问N位于 的倍数地址的字节数据类型,什么更好N?例如,在上面的结构体中,如果i位于地址XXX3(以 3 结尾,换句话说,不是 4 的倍数),为什么不读取从地址开始的单词XXX3?为什么一定是4的倍数?大多数 CPU 访问的地址是否仅为字大小的倍数?我相信 CPU 可以从内存中的任意字节开始读取一个字。我错了吗?
3 - 为什么编译器不重新排序成员以便占用尽可能多的空间?顺序重要吗?我不确定是否有人使用实际的偏移量来访问成员。这意味着如果有一个 struct X x,通常会像这样访问成员:x.inot *(&x + 4)。在后一种情况下,顺序实际上很重要,但在第一种情况下(我相信每个人都使用),顺序不重要。我必须注意,在这个例子中,这并不重要,因为如果也i出现在前面c,那么末尾会有 3 个字节的填充。我一般都问为什么? …
我最近总是遇到以下问题:
-march=native.Eigen::Quaternionf。在其他情况下,会EIGEN_UNALIGNED_ASSERT触发 ,这会导致此页面,我在代码中随处观察到其内容(据我所知)我想成为一个好公民,所以我尝试在一个最小的示例上重现该问题,并将其发布在 stackoverflow 或相关问题跟踪器中。然而,当我只提取触发问题的位时,我总是无法重现崩溃。我的猜测是,内存是否对齐(并且不需要特别注意)也取决于问题位置之前分配的内容,因此周围的代码有助于触发问题。
问题:我可以使用哪些技术和工具来有效确定 Linux 和/或 macOS 上的 C+14 中内存对齐相关崩溃的根源?