Malloc vs new — 다른 패딩


110

고성능 컴퓨팅 (10 ^ 5-10 ^ 6 코어)을 위해 MPI를 사용하는 우리 프로젝트에 대해 다른 사람의 C ++ 코드를 검토하고 있습니다. 이 코드는 서로 다른 아키텍처에서 (잠재적으로) 서로 다른 시스템 간의 통신을 허용하기위한 것입니다. 그는 다음과 같은 내용을 설명하는 주석을 작성했습니다.

우리는 일반적으로 newand를 사용 delete하지만 여기서는 mallocand를 사용 free합니다. 일부 컴파일러는 사용시 데이터를 다르게 패딩하여 new다른 플랫폼간에 데이터를 전송할 때 오류가 발생 하기 때문에 필요 합니다. 이것은 malloc.

이것은 표준 newmalloc질문 에서 내가 아는 어떤 것과도 맞지 않습니다 .

new / delete와 malloc / free의 차이점은 무엇입니까? 컴파일러가 객체의 크기를 다르게 계산할 수 있다는 생각을 암시합니다 (하지만 왜 그것이 sizeof? 를 사용하는 것과 다른지 ).

malloc 및 배치 new vs. new 는 상당히 인기있는 질문이지만 그렇지 않은 new생성자 를 사용하는 것에 대해서만 이야기 malloc합니다. 이는 이와 관련이 없습니다.

malloc은 정렬을 어떻게 이해합니까? 메모리가 제대로 중 하나에 정렬이 보장되는 것을 말한다 new거나 malloc하는 것은 내가 이전에 생각했던 것 것입니다.

내 생각 엔 그가 과거에 자신의 버그 시간을 좀 오진 및 추론 점이다 new그리고 malloc나는 사실이 아니다 아마 생각 패딩 서로 다른 양의를 제공합니다. 하지만 Google이나 이전 질문에서 답을 찾을 수 없습니다.

도와주세요, StackOverflow, 당신은 나의 유일한 희망입니다!


33
다양한 SO 쓰레드 연구에 +1!
iammilind 2012

7
+1 내가 오랫동안 본 적이있는 최고의 "다른 사람에게 물어보기 전에 도움을주는"연구 작업 중 하나입니다. 내가 이것을 몇 번 더 찬성 할 수 있기를 바랍니다.
WhozCraig 2011

1
전송 코드는 데이터가 특정 방식으로 정렬되어 있다고 가정합니까 (예 : 8 바이트 경계에서 시작)? 이 사이에 다를 수 mallocnew같은 new일부 환경 블록을 할당에서, 처음에 어떤 데이터를 추가하고,이 데이터 후에 오른쪽 위치에 대한 포인터를 리턴한다. (필자는 데이터 블록 내부에, 다른 사람들과 동의 mallocnew패딩의 동일한 종류를 사용해야합니다.)
Lindydancer

1
와우이 질문이 이렇게 인기가있을 줄은 몰랐어요! @Lindydancer, 8 바이트 경계가 가정되지 않는다고 생각합니다. 그래도 흥미로운 점.
hcarver 2012

1
다른 할당 방법을 사용하는 한 가지 이유는 "다른 사람"이 객체를 해제 할 때입니다. 이 "다른 사람"이 free를 사용하여 개체를 삭제하면 malloc을 사용하여 할당해야합니다. (패드 문제는 붉은 청어입니다.)
Lindydancer

답변:


25

IIRC에는 까다로운 점이 하나 있습니다. malloc모든 표준 유형에 대해 정렬 된 주소를 반환하도록 보장됩니다. n보다 크지 않은::operator new(n) 표준 유형에 대해 정렬 된 주소 만 반환하도록 보장되며 문자 유형이 아닌 경우 정렬 된 주소 만 반환하면됩니다.Tnew T[n]T .

그러나 이것은 플래그를 저장하기 위해 포인터의 아래쪽 몇 비트를 사용하거나 그렇지 않으면 주소에 의존하여 엄격하게 필요한 것보다 더 많은 정렬을 갖는 것과 같은 구현 특정 트릭을 할 때만 관련이 있습니다.

객체 내의 패딩에는 영향을주지 않으며, 차지하는 메모리를 할당 한 방법에 관계없이 반드시 정확히 동일한 레이아웃을 갖습니다. 따라서 차이로 인해 데이터 전송 오류가 발생할 수있는 방법을 알기가 어렵습니다.

그의 의견으로는 "malloc처럼 패딩 됨"또는 "새 것처럼 패딩 됨"여부에 관계없이 해당 주석의 작성자가 스택 또는 전역 객체에 대해 생각하는 징후가 있습니까? 그것은 아이디어가 어디에서 왔는지에 대한 단서를 줄 수 있습니다.

아마 혼란,하지만 어쩌면 그는 대한 얘기 코드 사이의 직선 차이보다 더 malloc(sizeof(Foo) * n)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배열은 전혀 패딩되지 않으므로 설명으로 "혼란"을 고수하겠습니다.
Steve Jessop

5

동료가 new[]/delete[]의 매직 쿠키를 염두에 두었을 수 있습니다 (이는 구현에서 배열을 삭제할 때 사용하는 정보입니다). 그러나 new[](할당 자와 반대되는)에서 반환 한 주소에서 시작하는 할당 이 사용 된 경우 이것은 문제가되지 않았습니다 .

포장 가능성이 더 높아 보입니다. ABI의 변형은 (예를 들어) 구조 끝에 추가 된 후행 바이트 수가 달라지는 결과를 초래할 수 있습니다 (이는 정렬의 영향을받으며 배열도 고려). malloc을 사용하면 구조의 위치를 ​​지정할 수 있으므로 외부 ABI로 쉽게 이동할 수 있습니다. 이러한 변형은 일반적으로 전송 구조의 정렬 및 패킹을 지정하여 방지됩니다.


2
이것이 제가 처음 생각했던 "구조체가 부분의 합보다 큽니다"문제였습니다. 아마도 이것이 그의 아이디어가 원래 나온 곳일 것입니다.
hcarver 2012

3

객체의 레이아웃은 malloc또는을 사용하여 할당되었는지 여부에 따라 달라질 수 없습니다 new. 둘 다 같은 종류의 포인터를 반환하며이 포인터를 다른 함수에 전달할 때 개체가 어떻게 할당되었는지 알 수 없습니다. 할당 방법 sizeof *ptr이 아니라의 선언에만 의존합니다 ptr.


3

그 쪽이 맞는 거 같아요. 패딩은 컴파일러가되지를 수행 new하거나 malloc. 패딩 고려 사항은 사용하지 않고 배열이나 구조체를 선언에도 적용되는 것 new또는 malloc전혀. 어떤 경우에는 내가 얼마나 다른 구현을 볼 수있는 동안 newmalloc나는 완전히 그들이 문제 플랫폼간에 데이터를 전송 될 수 있습니다 방식을 볼 실패, 플랫폼간에 코드를 포팅 할 때 문제가 발생할 수 있습니다.


나는 이전에 고려할 수있는 가정 거라고 new위한 좋은 래퍼로 malloc하지만 그렇지 않아 다른 답변에서 보인다 매우 사실. 패딩은 어느 쪽이든 동일해야한다는 합의가있는 것 같습니다. 플랫폼 간 데이터 전송 문제는 전송 메커니즘에 결함이있는 경우에만 발생한다고 생각합니다. :)
hcarver

0

MS Visual 컴파일러를 사용하여 평범한 이전 데이터 구조의 레이아웃을 제어하려면 #pragma pack(1). 예를 들어 gcc 와 같은 대부분의 컴파일러에서 이러한 사전 컴파일러 지시문이 지원된다고 가정 합니다.

이것은 빈 공간없이 구조의 모든 필드를 서로 뒤에서 정렬 한 결과입니다.

다른 쪽의 플랫폼이 동일한 작업을 수행하면 (즉, 패딩이 1 인 데이터 교환 구조를 컴파일 한 경우) 양쪽에서 검색된 데이터가 잘 맞습니다. 따라서 C ++에서 malloc을 사용할 필요가 없습니다.

최악의 경우에는 C ++에서 직접 malloc을 사용하는 대신 몇 가지 까다로운 작업을 수행하기 위해 new 연산자를 오버로드하는 것을 고려했을 것입니다.


데이터 구조 레이아웃을 제어하려는 상황은 무엇입니까? 그냥 궁금해.
hcarver

그리고 누구든지 지원 pragma pack하거나 유사한 컴파일러를 알고 있습니까? 나는 그것이 표준의 일부가 될 수 없다는 것을 알고 있습니다.
hcarver

예를 들어 gcc에서 지원합니다. 어떤 상황에서 내가 필요로했던 것 : 두 개의 다른 플레이트 폼 사이에서 바이너리 데이터 공유 : 윈도우와 팜 OS 사이, 윈도우와 리눅스 사이에서 바이너리 스트림 공유. gcc에 대한 링크 : gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html
Stephane Rolland

0

이것은 이것이 어디에서 왔는지에 대한 나의 추측입니다. 언급했듯이 문제는 MPI를 통한 데이터 전송에 있습니다.

개인적으로 MPI를 통해 송수신하려는 복잡한 데이터 구조의 경우 항상 모든 것을 문자 배열로 /에서 압축 해제하는 직렬화 / 역 직렬화 메서드를 구현합니다. 이제 패딩으로 인해 구조의 크기가 멤버의 크기보다 클 수 있다는 것을 알고 있으므로 데이터 구조의 패딩되지 않은 크기를 계산하여 얼마나 많은 바이트가 송수신되고 있는지 알 수 있습니다.

예를 들어 std::vector<Foo> A, 상기 기술로 MPI를 통해 송수신하려는 경우 결과 문자 배열의 크기를 A.size()*sizeof(Foo)일반적으로 가정하는 것은 잘못되었습니다 . 즉, serialize / deserialize 메서드를 구현하는 각 클래스는 배열의 크기를보고하는 메서드도 구현해야합니다 (또는 컨테이너에 배열을 저장하는 것이 더 좋습니다). 이것이 버그의 원인 이 될 수 있습니다 . 그러나 어떤 식 으로든 이 스레드에서 지적한 것처럼 newvs 와는 관련이 없습니다 malloc.


char 배열로 복사하는 것은 문제가 될 수 있습니다. 코어 중 일부는 little-endian 아키텍처에 있고 일부는 big-endian (아마도 가능하지는 않지만 가능함)에있을 수 있습니다. XDR로 인코딩해야하지만 사용자 정의 MPI 데이터 유형 만 사용할 수 있습니다. 그들은 쉽게 패딩을 고려합니다. 그러나 오해의 가능한 원인에 대해 여러분이 말하는 것을 볼 수 있습니다. 이것이 제가 "구조체가 부분의 합보다 큽니다"문제라고 부르는 것입니다.
hcarver

예, MPI 데이터 유형을 정의하는 것은이를 수행하는 또 다른 / 올바른 방법입니다. 엔디안에 대한 좋은 점. 하지만 실제 클러스터에서 일어날 수 있을지 의심 스럽습니다. 어쨌든, 난 ... 그들은 같은 전략을 따르는 경우에,이 버그가 생길 수 있습니다 생각
mmirzadeh

0

C ++에서 : new 키워드는 일부 데이터 구조와 관련하여 특정 바이트의 메모리를 할당하는 데 사용됩니다. 예를 들어, 일부 클래스 또는 구조를 정의했으며 해당 객체에 대한 메모리를 할당하려고합니다.

myclass *my = new myclass();

또는

int *i = new int(2);

그러나 모든 경우에 정의 된 데이터 유형 (class, struct, union, int, char 등 ...)이 필요하며 해당 객체 / 변수에 필요한 메모리의 바이트 만 할당됩니다. (즉, 해당 데이터 유형의 배수).

그러나 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
나는 당신이 당신의 대답을 조금 더 주장해야한다고 생각합니다.
Carlo

이것은 패딩으로 다른 일을하는 그들에 대한 질문을 다루지 않는 것 같습니다.
hcarver
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.