내가 무언가를 '던질'때 메모리에 어디에 저장됩니까?


82

나는 무언가가 thrown 일 때 스택이 잡힌 지점까지 '해제'되고 각 함수 컨텍스트의 스택에있는 클래스 인스턴스의 소멸자가 실행된다는 것을 이해합니다 (소멸자에서 예외를 던져서는 안되는 이유입니다 -당신은 두 번째 것을 던질 수 있습니다) ...하지만 이것이 발생하는 동안 내가 던진 물건이 기억에 어디에 저장되는지 궁금합니다.

구현에 따라 다릅니 까? 그렇다면 가장 널리 사용되는 컴파일러에서 사용하는 특정 방법이 있습니까?


1
좋은 질문입니다. 표준이 스택이 있어야한다고 말하지 않기 때문에 표준에 의해 지정되지 않았을 것입니다. 실제로 힙에 할당되고 catch 블록이 종료 될 때 해제됩니까?
Kerrek SB

@Kerrek : 나는 더 가능성이 높다고 생각한다, 객체는 "맨 아래"에있는 스택에 배치된다. 그런 다음 위쪽으로 긴장을 풀고 그것이 어디에 있었는지 기억하고, 일단 풀기를 마치면 (모든 catch 절에 참조로 예외를 처리하고 되돌릴 수있는 기회를 제공하는 것을 포함하여 raise) 파기하십시오. 힙 할당의 문제는 예외 할당 시도가 실패하면 어떻게합니까? 중단해야합니다 (공간 부족으로 인해 스택에 "실패"하는 경우 스택 오버플로와 마찬가지로). Java와 달리 구현은 대신 다른 예외를 throw 할 수 없습니다.
Steve Jessop 2011

@Steve : 또한 가능합니다-Kiril의 기사에 따르면 예외는 스택에 할당되고 보조 정보 구조는 주소와 삭제 자 등을 기록하지만 구현이 원하는 방식으로 자유롭게 수행 할 수 있다고 생각합니까?
Kerrek SB

@Kerrek : 예, 실제로 예외를 던져야한다는 제약 조건과 스택 부족으로 인해 구현이 그러한 책임을 회피 할 수 있다는 일반적인 문제가 있습니다. :-) 스택에 넣으면 예외가 발생하기 때문입니다. throw 식 의 정적 형식에 따라 전체 함수의 스택 프레임에는 해당 형식을 throw하는 데 필요한 모든 공간이 포함될 수 있지만 MSVC가 그렇게하는지는 모르겠습니다.
Steve Jessop

답변:


51

예, 대답은 컴파일러에 따라 다릅니다.

내 컴파일러 ( g++ 4.4.3)를 사용한 빠른 실험 은 런타임 라이브러리가 먼저 malloc예외에 대해 메모리를 시도하고 실패하면 데이터 세그먼트에있는 프로세스 전체 "비상 버퍼"내에 공간을 할당하려고 시도한다는 것을 보여줍니다. 그래도 해결되지 않으면 std::terminate().

비상 버퍼의 주요 목적은 std::bad_alloc프로세스의 힙 공간이 부족한 후에 throw 할 수 있는 것 같습니다 (이 경우 malloc호출이 실패 함).

관련 기능은 __cxa_allocate_exception다음과 같습니다.

extern "C" void *
__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
{
  void *ret;

  thrown_size += sizeof (__cxa_refcounted_exception);
  ret = malloc (thrown_size);

  if (! ret)
    {
      __gnu_cxx::__scoped_lock sentry(emergency_mutex);

      bitmask_type used = emergency_used;
      unsigned int which = 0;

      if (thrown_size > EMERGENCY_OBJ_SIZE)
        goto failed;
      while (used & 1)
        {
          used >>= 1;
          if (++which >= EMERGENCY_OBJ_COUNT)
            goto failed;
        }

      emergency_used |= (bitmask_type)1 << which;
      ret = &emergency_buffer[which][0];

    failed:;

      if (!ret)
        std::terminate ();
    }

  // We have an uncaught exception as soon as we allocate memory.  This
  // yields uncaught_exception() true during the copy-constructor that
  // initializes the exception object.  See Issue 475.
  __cxa_eh_globals *globals = __cxa_get_globals ();
  globals->uncaughtExceptions += 1;

  memset (ret, 0, sizeof (__cxa_refcounted_exception));

  return (void *)((char *)ret + sizeof (__cxa_refcounted_exception));
}

이 계획이 얼마나 전형적인 지 모르겠습니다.


"어떤 경우에는 malloc호출이 실패 할 것"입니다. 보통은 아니지만 반드시 그런 것은 아닙니다.
Ayxan Haqverdili

20

에서 이 페이지 :

예외가 발생하려면 스토리지가 필요합니다. 이 저장소는 처리기에서 사용되므로 스택이 풀리는 동안 유지되어야하며 스레드로부터 안전해야합니다. 따라서 구현시 메모리 부족 조건에서 bad_alloc 예외 발생을 지원 하기 위해 비상 버퍼제공 할 수 있지만 예외 객체 저장소는 일반적으로 힙에 할당됩니다 .

이제 이것은 Itanium ABI 일 뿐이며 GCC, Clang 및 MSVC와 관련된 세부 정보를 찾고 있습니다. 그러나 표준은 아무것도 지정하지 않으며 이것은 예외 저장소를 구현하는 명백한 방법 인 것 같습니다.


1
아직도 세부 사항을 찾고 계십니까? 때로는 하나 이상의 답 : 받아 들일 수 있도록 좋은 것
sje397

4

이것이 귀하의 질문에 대한 답이 될지 모르겠지만 (C ++ 컴파일러가 예외 처리를 구현하는 방법) 은 예외 처리에 대한 훌륭한 기사입니다. 나는 그것을 적극 추천합니다 (:

짧은 답변에 대해 죄송합니다. 기사의 전체 정보가 훌륭합니다. 여기에서 일부 정보를 선택하여 게시 할 수 없습니다.


excpt_info해당 페이지에서 검색 하면 MSVC가 수행하는 방법에 대한 정보가 제공됩니다.
Steve Jessop 2011-07-07

1
이 링크는 실제로 좋은 구현에서이를 수행하지 않는 방법을 설명합니다. 일부 오래된 VC ++가 이와 같은 것을 사용했다는 것을 알고 있지만 최신 컴파일러에서 찾을 수 있을지 의심 스럽습니다.
James Kanze 2011

0

C ++ 표준은 일반적으로 언어의 동작 방식을 지정하지만 컴파일러가 해당 동작을 구현하는 방식은 지정하지 않습니다. 이 질문이 그 범주에 속한다고 생각합니다. 이와 같은 것을 구현하는 가장 좋은 방법은 머신의 특성에 따라 다릅니다. 일부 프로세서에는 많은 범용 레지스터가 있고 일부는 거의 없습니다. 프로세서는 예외를 위해 특수 레지스터로 빌드 될 수도 있습니다.이 경우 컴파일러는 해당 기능을 자유롭게 활용할 수 있어야합니다.


-2

글쎄, 그것은 풀릴 것이기 때문에 스택에있을 수 없으며 힙에있을 수도 없습니다 std::bad_alloc. 시스템이 던질 수 없다는 것을 의미하기 때문입니다 . 그 외에는 구현에 따라 다릅니다. 구현이 지정되지 않았으며 (문서화되어야 함) 지정되지 않았습니다. (더 이상 메모리가없는 경우에도 제한된 수의 예외를 허용하는 일종의 긴급 백업이있는 한 구현에서 대부분의 경우 힙을 사용할 수 있습니다.)


3
당신의 대답은 그 자체로 모순됩니다.
궤도의 가벼운 경주

어떻게? 표준에 내포 된 구현에 대한 제약을 나타냅니다.
James Kanze 2011

한 가지 예 : "힙에있을 수 없습니다."... "구현은 대부분 힙을 사용할 수 있습니다." 또한 다른 답변에서 설명한 것처럼 답변의 전반부 전체가 잘못되었습니다 (실제로 부분적으로 당신의 두 번째 부분에서!).
밝기 경주 궤도에

표준이 std::bad_alloc작동 해야 합니다. 이는 구현에서 힙을 체계적으로 사용할 수 없음을 의미합니다. 표준은 그것을 허용하지 않습니다. 나는 내 주장을 표준에 근거하고있다.
James Kanze 2011

FSVO는 "체계적으로"맞습니다. 그러나 답변의 두 번째 부분에서 언급했듯이 구현은 실제로 대안과 함께 heap ^ H ^ H ^ H ^ Hfreestore를 사용할 수 있습니다.
밝기 경주 궤도에
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.