Bir şeyi `` attığımda '' hafızada nerede saklanır?


82

Bir şey thrown olduğunda, yığının yakalandığı noktaya kadar 'çözüldüğünü' ve her işlev bağlamında yığındaki sınıf örneklerinin yıkıcılarının çalıştırıldığını anlıyorum (bu nedenle bir yıkıcıdan bir istisna atmamalısınız) - ikinci bir tane atabilirsiniz) ... ama bu olurken fırlattığım nesnenin hafızada nerede saklandığını merak ediyorum?

Uygulamaya bağlı mı? Öyleyse, en popüler derleyiciler tarafından kullanılan belirli bir yöntem var mı?


1
İyi soru - muhtemelen standart tarafından belirtilmemiştir, çünkü standart bir yığına sahip olmanız gerektiğini bile söylemiyor. Pratik olarak, belki de yığın üzerine tahsis edilir ve catch bloğu çıkınca serbest bırakılır?
Kerrek SB

@Kerrek: Bence nesne yığının en altına "en altta" yerleştirildi. Sonra yukarı doğru gevşeyin, nerede olduğunu hatırlayın ve gevşemeyi bitirdikten sonra (herhangi bir yakalama maddesine istisnayı referans olarak ele alma ve reddetme fırsatı vermek dahil raise), onu yok edin. Yığın tahsisi ile ilgili sorun, istisnayı tahsis etme girişiminiz başarısız olursa ne yapacağınızdır? İptal etmeniz gerekir (tıpkı yer yetersizliğinden dolayı yığına yerleştirmek "başarısız olursa" yığın taşması durumunda yapacağınız gibi). Java'nın aksine, uygulamanın bunun yerine farklı bir istisna atmasına izin verilmez.
Steve Jessop

@Steve: Ayrıca mümkün - Kiril'in makalesi, istisnanın yığına tahsis edildiğini ve yardımcı bir bilgi yapısının adresini ve siliciyi vb. Kaydettiğini söylüyor, ancak uygulamaların bunu istedikleri şekilde yapmakta özgür olduğunu düşünüyorum.
Kerrek SB

@Kerrek: evet, aslında istisnayı atmak zorunda olduğu kısıtlamaya tabi ve yığının tükenmesinin bu tür sorumluluklardan kurtulmasına izin veren olağan sorunu var :-) Eğer onu yığına koyarsanız, o zaman istisnalar atıldığı için tarafından statik atış ifadesinin türü, bütün işlevi için yığın çerçevesi ben MSVC bunu yapmaz bilmiyorum rağmen, bu tür atmak için gereken her türlü boşluk içerebilir.
Steve Jessop

Yanıtlar:


51

Evet, cevap derleyiciye bağlıdır.

Derleyicim ( g++ 4.4.3) ile yapılan hızlı bir deney , çalışma zamanı kitaplığının ilk önce mallocistisna için belleğe almayı denediğini ve başarısız olursa, veri segmentinde yaşayan süreç çapında bir "acil durum arabelleği" içinde alan ayırmaya çalıştığını ortaya koyuyor . Bu işe yaramazsa, çağırıyor std::terminate().

Görünüşe göre acil durum tamponunun ana amacı std::bad_alloc, işlemin yığın alanı tükendikten sonra (bu durumda mallocçağrı başarısız olacaktır) fırlatmaktır .

İlgili işlev __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));
}

Bu planın ne kadar tipik olduğunu bilmiyorum.


"bu durumda mallocçağrı başarısız olur", genellikle, ancak zorunlu olarak değil.
Ayxan Haqverdili

20

Gönderen bu sayfada :

Atılan istisnalar için depolama gereklidir. Bu depolama, işleyici tarafından kullanılacağından yığın çözülürken kalıcı olmalıdır ve iş parçacığı açısından güvenli olmalıdır. Özel durum nesnesi depolaması, bu nedenle normalde öbek içinde tahsis edilecektir , ancak uygulamalar, düşük bellek koşulları altında bad_alloc istisnalarının atılmasını desteklemek için bir acil durum arabelleği sağlayabilir .

Şimdi, bu sadece Itanium ABI ve ben GCC, Clang ve MSVC'ye özgü ayrıntıları arıyorum. Bununla birlikte, standart hiçbir şey belirtmez ve bu, istisna depolamayı uygulamanın açık bir yolu gibi görünmektedir, bu yüzden ...


1
Hala ayrıntılar mı arıyorsunuz? Bazen birden fazla yanıtı kabul edebilmek güzel olurdu :)
sje397

4

Bunun sorunuza cevap verip vermeyeceğini bilmiyorum, ancak bu (Bir C ++ derleyicisi istisna işlemeyi nasıl gerçekleştirir) istisna işleme hakkında mükemmel bir makale:. Şiddetle tavsiye ederim (:

Kısa cevap için üzgünüm, ancak makaledeki tüm bilgiler harika, burada bazı bilgileri seçip gönderemiyorum.


excpt_infoBu sayfada arayın , MSVC'nin bunu nasıl yaptığı hakkında bazı bilgiler verir.
Steve Jessop

1
Bu bağlantı gerçekten iyi bir uygulamada nasıl yapılmayacağını açıklıyor. Bazı eski VC ++ 'nın böyle bir şey kullandığını biliyorum, ancak bunu herhangi bir modern derleyicide bulacağınızdan şüpheliyim.
James Kanze

0

C ++ standardı genellikle dilin nasıl davrandığını belirtir, ancak derleyicinin bu davranışı nasıl uygulaması gerektiğini belirtmez. Sanırım bu soru bu kategoriye giriyor. Bunun gibi bir şeyi uygulamanın en iyi yolu makinenin özelliklerine bağlıdır - bazı işlemcilerin çok sayıda genel amaçlı yazmaçları vardır, bazılarının ise çok azı vardır. Bir işlemci, istisnalar için özel bir kayıtla bile oluşturulabilir, bu durumda derleyici bu özellikten yararlanmakta özgür olmalıdır.


-2

Şey, yığının üzerinde olamaz, çünkü bu çözülecek ve yığında olamaz, çünkü bu, sistemin muhtemelen fırlatamayacağı anlamına gelir std::bad_alloc. Bunun dışında, tamamen uygulamaya bağlıdır: uygulama belirtilmemiş (belgelenmelidir), ancak belirtilmemiş. (Bellek olmadığında bile sınırlı sayıda istisnaya izin verecek bir tür acil durum yedeklemesi olduğu sürece, bir uygulama çoğu zaman yığını kullanabilir.)


3
Cevabınız kendisiyle çelişiyor.
Orbit'te Hafiflik Yarışları

Nasıl? Standartta örtülü olan bir uygulama üzerindeki kısıtlamaları sunar.
James Kanze

Bir örnek: "yığın üzerinde olamaz" ... "Bir uygulama çoğu zaman öbeği kullanabilir". Ek olarak, diğer cevaplarda (ve aslında sizin ikinci bölümünüzde kısmen!) Açıklandığı gibi, cevabın ilk yarısı yanlıştır.
Orbit'te Hafiflik Yarışları

Standart std::bad_allocçalışmayı gerektirir . Bu, bir uygulamanın sistematik olarak yığını kullanamayacağı anlamına gelir. Standart buna izin vermiyor. İddialarımı standartlara dayandırıyorum.
James Kanze

"Sistematik olarak" FSVO, bu doğru. Bununla birlikte, cevabınızın ikinci bölümünde belirttiğiniz gibi, bir uygulama gerçekten de ^ H ^ H ^ H ^ Hfreestore yığınını alternatiflerle birlikte kullanabilir.
Orbit'te Hafiflik Yarışları
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.