Malloc与新版-不同的填充


110

我正在审查使用MPI进行高性能计算(10 ^ 5-10 ^ 6内核)的项目的其他人的C ++代码。该代码旨在允许(可能)不同体系结构上的不同机器之间进行通信。他写了一条评论,内容大致如下:

我们通常使用newdelete,但是在这里我使用mallocfree。这是必要的,因为某些编译器在new使用时会以不同的方式填充数据,从而导致在不同平台之间传输数据时出错。不会发生这种情况malloc

这与我从标准newvs malloc问题中了解到的任何内容都不符。

new / delete和malloc / free有什么区别?这暗示了编译器可以对对象的大小进行不同的计算(但是,为什么这与使用sizeof?有所不同)。

malloc和placement new vs. new是一个相当受欢迎的问题,但仅涉及newmalloc不使用构造函数的情况下的使用,与此无关。

malloc如何理解对齐方式?说,保证内存可以正确地与任一newmalloc这是我以前认为的。

我的猜测是,他在过去的某个时候误诊了自己的错误,并推断出该错误newmalloc进行了不同程度的填充,我认为这可能是不正确的。但我找不到Google或其他任何问题的答案。

帮我,StackOverflow,您是我唯一的希望!


33
+1仅用于研究各种SO线程!
iammilind 2012年

7
+1很长时间以来,我就在SO上轻松找到最好的“先问别人”的研究工作之一。希望我能再投票几次。
WhozCraig

1
传输代码是否假设数据以任何特定方式对齐,例如,它以八字节边界开始?malloc和之间可能有所不同new,因为new在某些环境中分配一个块,将一些数据添加到开头,并在该数据之后立即返回指向某个位置的指针。(我同意其他人,在数据块内,malloc并且new必须使用相同的填充。)
Lindydancer 2012年

1
哇,我没想到这个问题会如此受欢迎!@Lindydancer,我认为不假定任何8字节边界。有趣的一点。
hcarver 2012年

1
之所以使用一种分配方法而不是另一种分配方法,是因为“其他人”正在释放对象。如果此“其他人”使用free删除了对象,则必须使用malloc进行分配。(便笺本是鲱鱼。)
Lindydancer 2012年

Answers:


25

IIRC有一个挑剔的地方。malloc保证返回一个与任何标准类型对齐的地址。::operator new(n)只能保证返回不大于n的任何标准类型的对齐地址,如果T不是字符类型,则new T[n]仅需要返回的地址对齐T

但这仅在您玩特定于实现的技巧时才有意义,例如使用指针的底部几位来存储标志,或者以其他方式依赖该地址来比其严格需要的对齐方式更多。

它不会影响对象内的填充,对象的布局必须完全相同,无论您如何分配占用的内存。因此,很难看到差异如何导致数据传输错误。

有没有迹象表明该评论的作者对堆栈或全局对象中的对象有何看法,无论他认为是“像malloc一样填充”还是“像新一样那样填充”?这可能为该想法的来源提供线索。

也许他很困惑,但是也许他在谈论的代码不仅仅是malloc(sizeof(Foo) * n)vs与之间的直接区别new Foo[n]。也许更像是:

malloc((sizeof(int) + sizeof(char)) * n);

struct Foo { int a; char b; }
new Foo[n];

也就是说,也许他说的是 “我使用malloc”,但意思是 “我将数据手动打包到未对齐的位置,而不是使用结构”。malloc为了手动打包该结构,实际上并不需要,但是没有意识到这是一个较小的混乱程度。必须定义通过导线发送的数据布局。使用该结构时,不同的实现将不同地填充数据。


感谢有关对齐的要点。有问题的数据是一个char数组,因此我怀疑这不是对齐的东西,也不是结构的东西-尽管那也是我的第一个想法。
hcarver 2012年

5
@Hbcdev:好的char数组根本不会被填充,因此我会坚持使用“ confused”作为解释。
史蒂夫·杰索普

5

您的同事可能已经想到了new[]/delete[]魔术cookie(这是实现在删除数组时使用的信息)。但是,如果使用从返回的地址开始的分配new[](而不是分配器的分配),这将不是问题。

包装似乎更有可能。ABI的变化可能(例如)导致在结构的末尾添加不同数量的尾随字节(这受对齐方式的影响,还应考虑数组)。使用malloc,可以指定结构的位置,从而更容易移植到外部ABI。通常通过指定转移结构的对齐方式和堆积方式来防止这些变化。


2
这是我首先想到的“结构大于其各部分之和”的问题。也许这就是他的想法最初来自何处。
hcarver 2012年

3

对象的布局不能取决于它是使用malloc还是分配的new。它们都返回相同类型的指针,当您将此指针传递给其他函数时,它们将不知道对象的分配方式。sizeof *ptr仅取决于的声明ptr,而不是如何分配的。


3

我想你是对的。填充不是由new或由编译器完成的malloc。即使您声明一个数组或结构而不使用newmalloc根本不使用,填充注意事项也将适用。在任何情况下,尽管我可以看到在平台之间移植代码时不同的实现方式newmalloc可能引起问题,但我完全看不到它们如何在平台之间传输数据时会引起问题。


我以前以为你可以考虑new作为一个很好的包装器malloc,但它与其他的答案,这不是显得真实。共识似乎是两者中的填充都应该相同。我认为,仅当您的传输机制存在缺陷时,才在平台之间传输数据的问题:)
hcarver 2012年

0

当我想用MS Visual编译器控制普通旧数据结构的布局时,请使用#pragma pack(1)。我想大多数编译器都支持这样的precompiler指令,例如gcc

这样的结果是将结构的所有字段一个接一个地对齐,而没有空白。

如果另一端的平台执行相同的操作(即,使用填充1编译其数据交换结构),则从两侧检索的数据都非常合适。因此,我从不需要在C ++中使用malloc。

最糟糕的是,我会考虑重载new运算符,以便它执行一些棘手的事情,而不是直接在C ++中使用malloc。


您想在什么情况下控制数据结构的布局?只是好奇。
hcarver 2012年

有人知道支持pragma pack或类似的编译器吗?我知道它不会成为标准的一部分。
hcarver 2012年

例如,gcc支持它。在什么情况下我需要这样做:在两种不同的平台之间共享二进制数据:在Windows和PalmOS之间,在Windows和Linux之间共享二进制流。有关gcc的链接:gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html
Stephane Rolland

0

这是我对这东西从何而来的疯狂猜测。如您所述,问题在于通过MPI进行数据传输。

就个人而言,对于我想通过MPI发送/接收的复杂数据结构,我总是实现序列化/反序列化方法,将整个内容打包/解压缩为一个字符数组。现在,由于填充,我们知道该结构的大小可能大于其成员的大小,因此还需要计算数据结构的未填充大小,以便我们知道正在发送/接收多少个字节。

例如,如果您想std::vector<Foo> A使用上述技术通过MPI 发送/接收,则假定生成的char数组的大小通常是错误的A.size()*sizeof(Foo)。换句话说,实现序列化/反序列化方法的每个类也应实现报告数组大小的方法(或者最好将数组存储在容器中)。这可能成为错误的原因。但是,正如该线程中所指出的,与newvs 无关的一种或另一种方式malloc


复制到char数组可能会出现问题-您的某些核心可能在小端架构上,而某些在大端架构上(可能,但可能)。您必须对其进行XDR编码,但是您可以只使用用户定义的MPI数据类型。他们很容易考虑填充。但是,我可以看到您对误解的可能原因在说什么,这就是我所说的“结构大于其各部分之和”的问题。
hcarver 2012年

是的,定义MPI数据类型是另一种/正确的方法。关于字节序的好点。虽然,我真的怀疑在实际集群上会发生这种情况。无论如何,我认为如果他们采用相同的策略,则可能会导致错误……
mmirzadeh 2012年

0

在c ++中: new关键字用于相对于某些数据结构分配某些特定的内存字节。例如,您已经定义了一些类或结构,并且想要为其对象分配内存。

myclass *my = new myclass();

要么

int *i = new int(2);

但是在所有情况下,您都需要定义的数据类型(类,结构,联合,整数,字符等),并且仅会分配其对象/变量所需的内存字节。(即该数据类型的倍数)。

但在使用malloc()方法的情况下,您可以分配任何字节的内存,而不必始终指定数据类型。在这里,您几乎可以通过malloc()观察到它:

void *v = malloc(23);

要么

void *x = malloc(sizeof(int) * 23);

要么

char *c = (char*)malloc(sizeof(char)*35);

-1

malloc是函数类型,而new是c ++中c ++中的数据类型,如果我们使用malloc超过了我们必须的值,则应该使用typecast,否则编译器会给您错误,并且如果我们使用新的数据类型来分配内存,那么我们就不需要了打字


1
我认为您应该尝试对您的答案进行更多讨论。
卡罗

这似乎没有解决他们用填充物做不同事情的问题,这是我在上面真正询问的问题。
hcarver 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.