programing

malloc은 얼라인먼트를 어떻게 이해하나요?

prostudy 2022. 6. 7. 21:28
반응형

malloc은 얼라인먼트를 어떻게 이해하나요?

여기서 발췌한 다음에

pw = (widget *)malloc(sizeof(widget));

raw 스토리지를 할당합니다.실제로 malloc 호출은 유형 위젯 개체를 저장할 수 있을 만큼 충분히 크고 적절하게 정렬된 스토리지를 할당합니다.

허브 서터의 빠른 pimpl도 볼 수 있다고 그는 말했다.

얼라인먼트임의의 메모리 얼라인먼트new 또는 malloc을 통해 동적으로 할당되는 메모리는 모든 유형의 오브젝트에 대해 적절하게 정렬이 보장되지만 동적으로 할당되지 않은 버퍼에는 이러한 보장이 없습니다.

궁금한데, malloc은 커스텀 타입의 얼라인먼트를 어떻게 알 수 있을까요?

정렬 요건은 재귀적입니다.임의의 위치 맞추기struct단순히 그 멤버 중 가장 큰 얼라인먼트이며, 이는 재귀적으로 이해됩니다.

예를 들어, 각 기본 유형의 정렬이 크기와 동일하다고 가정할 때(일반적으로 항상 해당되는 것은 아님),struct X { int; char; double; }의 정렬이 있다double2배 크기(예: 4(int), 1(char), 3(char), 8(double))의 배수로 패딩됩니다.struct Y { int; X; float; }의 정렬이 있다X이것은 가장 크고, 의 정렬과 동일합니다.double,그리고.Y4(int), 4(패딩), 16(X), 4(플로트), 4(패딩)가 적절히 배치됩니다.

(모든 숫자는 예에 불과하며 사용하시는 머신에 따라 다를 수 있습니다.)

따라서 기본 유형으로 세분화하면 몇 가지 기본 정렬만 알 수 있으며, 그 중 가장 큰 것이 잘 알려져 있습니다.C++는 타입도 정의합니다.max_align_t 정렬이 가장 큰 정렬입니다.

모든.malloc()그 값의 배수인 주소를 선택해야 합니다.

Herb Sutter 인용문의 가장 적절한 부분은 굵은 글씨로 표시한 부분이라고 생각합니다.

얼라인먼트임의의 메모리 얼라인먼트new 또는 malloc을 통해 동적으로 할당되는 메모리는 모든 유형의 오브젝트에 대해 적절하게 정렬이 보장되지만 동적으로 할당되지 않은 버퍼에는 이러한 보장이 없습니다.

어떤 타입을 생각하고 있는지 알 필요가 없습니다.어느 타입에도 대응하고 있기 때문입니다.예를 들어, 4바이트 워드가 있는 시스템은 최대 4바이트 얼라인먼트를 가질 수 있습니다.

이는 부분적으로 다음과 같은 man-page를 통해서도 알 수 있습니다.

malloc()그리고.calloc()함수는 할당된 메모리로 포인터를 반환합니다.이 메모리는 모든 종류의 변수에 적합하게 정렬되어 있습니다.

malloc의 파라미터는 총 크기이기 때문에 무엇을 할당하고 있는지 알 수 없습니다.어떤 물체에 대해서도 안전한 정렬에 맞출 수 있습니다.

이 유일한 정보는malloc()can use는 전달된 요청 크기입니다.일반적으로 전달된 크기를 2의 가장 큰(또는 같은) 제곱으로 반올림하고 해당 값에 따라 메모리를 정렬하는 등의 작업을 수행할 수 있습니다.얼라인먼트 값에도 상한(예: 8바이트)이 있을 수 있습니다.

위의 내용은 가상적인 설명이며 실제 구현은 사용 중인 머신 아키텍처와 런타임 라이브러리에 따라 달라집니다.아마도 당신의malloc()는 항상 8바이트로 정렬된 블록을 반환하며 다른 작업을 수행할 필요가 없습니다.

1) 모든 정렬의 최소 공배수로 정렬합니다. 예를 들어, int는 4바이트 정렬이 필요하지만 포인터는 8바이트 정렬이 필요한 경우 모든 것을 8바이트 정렬에 할당합니다.이렇게 하면 모든 것이 정렬됩니다.

2) size 인수를 사용하여 올바른 정렬을 결정합니다.작은 크기의 경우 다음과 같은 유형을 추론할 수 있습니다.malloc(1)(다른 타입의 사이즈가 1이 아닌 경우는 제외)는 항상 char입니다.C++new는 타입이 안전하다는 장점이 있기 때문에 항상 이 방법으로 정렬 결정을 내릴 수 있습니다.

C++11 이전에는 정확한 값을 알 수 없는 가장 큰 얼라인먼트를 사용하여 malloc/calloc이 여전히 이와 같이 동작하는 것으로 매우 간단하게 처리되었습니다.즉, malloc 할당이 모든 유형에 대해 올바르게 정렬되었음을 의미합니다.

얼라인먼트를 잘못하면 규격에 따라 정의되지 않은 동작이 발생할 수 있지만 x86 컴파일러는 관대하고 퍼포먼스가 떨어지기만 합니다.

컴파일러 옵션 또는 지시어를 사용하여 얼라인먼트를 조정할 수도 있습니다.(예를 들어 Visual Studio용 pragma 팩).

그러나 새로운 배치의 경우 C++11은 alignofalignas라는 새로운 키워드를 제공합니다.다음은 컴파일러의 최대 정렬이 1보다 클 경우의 영향을 나타내는 코드입니다.아래의 첫 번째 배치는 자동으로 양호하지만 두 번째 배치는 그렇지 않습니다.

#include <iostream>
#include <malloc.h>
using namespace std;
int main()
{
        struct A { char c; };
        struct B { int i; char c; };

        unsigned char * buffer = (unsigned char *)malloc(1000000);
        long mp = (long)buffer;

        // First placment new
        long alignofA = alignof(A) - 1;
        cout << "alignment of A: " << std::hex << (alignofA + 1) << endl;
        cout << "placement address before alignment: " << std::hex << mp << endl;
        if (mp&alignofA)
        {
            mp |= alignofA;
            ++mp;
        }
        cout << "placement address after alignment : " << std::hex <<mp << endl;
        A * a = new((unsigned char *)mp)A;
        mp += sizeof(A);

        // Second placment new
        long alignofB = alignof(B) - 1;
        cout << "alignment of B: " <<  std::hex << (alignofB + 1) << endl;
        cout << "placement address before alignment: " << std::hex << mp << endl;
        if (mp&alignofB)
        {
            mp |= alignofB;
            ++mp;
        }
        cout << "placement address after alignment : " << std::hex << mp << endl;
        B * b = new((unsigned char *)mp)B;
        mp += sizeof(B);
}

이 코드의 성능은 비트 연산을 통해 향상될 수 있습니다.

편집: 고가의 모듈로 연산을 비트 연산으로 대체.여전히 누군가 더 빨리 뭔가를 찾길 바라고 있어

언급URL : https://stackoverflow.com/questions/8752546/how-does-malloc-understand-alignment

반응형