溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

js引擎SemiSpace怎么實現(xiàn)

發(fā)布時間:2021-12-17 09:34:54 來源:億速云 閱讀:121 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“js引擎SemiSpace怎么實現(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“js引擎SemiSpace怎么實現(xiàn)”吧!

1 SemiSpace

SemiSpace是管理新生代內(nèi)存的類。

   
     
 
    
    

// SemiSpace in young generation
//
// A semispace is a contiguous chunk of memory. The mark-compact collector
// uses the memory in the from space as a marking stack when tracing live
// objects.

class SemiSpace  BASE_EMBEDDED {
public:
 // Creates a space in the young generation. The constructor does not
 // allocate memory from the OS.  A SemiSpace is given a contiguous chunk of
 // memory of size 'capacity' when set up, and does not grow or shrink
 // otherwise.  In the mark-compact collector, the memory region of the from
 // space is used as the marking stack. It requires contiguous memory
 // addresses.
 SemiSpace(int initial_capacity, int maximum_capacity);

 // Sets up the semispace using the given chunk.
 bool Setup(Address start, int size);

 // Tear down the space.  Heap memory was not allocated by the space, so it
 // is not deallocated here.
 void TearDown();

 // True if the space has been set up but not torn down.
 bool HasBeenSetup() { return start_ != NULL; }


 bool Double();

 // Returns the start address of the space.
 Address low() { return start_; }
 // Returns one past the end address of the space.
 Address high() { return low() + capacity_; }

 // Age mark accessors.
 Address age_mark() { return ag偏移_mark_; }
 void set_age_mark(Address mark) { age_mark_ = mark; }

 // True if the address is in the address range of this semispace (not
 // necessarily below the allocation pointer).
 // 判斷地址a是否在該對象管理的內(nèi)存中,&address_mask即讓a減去size-1的大小。如果等于start說明在管理范圍內(nèi)
 bool Contains(Address a) {
   return (reinterpret_cast<uint32_t>(a) & address_mask_)
          == reinterpret_cast<uint32_t>(start_);
 }

 // True if the object is a heap object in the address range of this
 // semispace (not necessarily below the allocation pointer).
 // 類似上面的邏輯,但是堆對象低位是標(biāo)記,判斷時候需要處理一下,加SetUp
 bool Contains(Object* o) {
   return (reinterpret_cast<uint32_t>(o) & object_mask_) == object_expected_;
 }

 // The offset of an address from the begining of the space.
 // 距離開始地址的p
 int SpaceOffsetForAddress(Address addr) { return addr - low(); }

private:
 // The current and maximum capacity of the space.
 int capacity_;
 int maximum_capacity_;

 // The start address of the space.
 Address start_;
 // Used to govern object promotion during mark-compact collection.
 Address age_mark_;

 // Masks and comparison values to test for containment in this semispace.
 // 見SetUp函數(shù)
 uint32_t address_ma函數(shù)
 uint32_t object_mask_;
 uint32_t object_expected_;

public:
 TRACK_MEMORY("SemiSpace")
};

             

下面是實現(xiàn)

   
     
 
    
    

SemiSpace::SemiSpace(int initial_capacity, int maximum_capacity)
   : capacity_(initial_capacity), maximum_capacity_(maximum_capacity),
     start_(NULL), age_mark_(NULL) {
}

// 設(shè)置管理的地址范圍
bool SemiSpace::Setup(Address start, int size) {
 ASSERT(size == maximum_capacity_);
 // 判斷地址的有效性
 if (!MemoryAllocator::CommitBlock(start, capacity_)) return false;
 // 管理地址空間的首地址
 start_ = start;
 // 低于有效范圍的掩碼,即保證相與后的值小于等于管理的地址范圍
 address_mask_ = ~(size - 1);
 // 計算對象地址掩碼,低位是標(biāo)記位,判斷的時候需要保留
 object_mask_ = address_mask_ | kHeapObjectTag;
 // 見contains函數(shù),對象地址里低位是標(biāo)記位,判斷的時候需要帶上
 object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag;
 // gc相關(guān)
 age_mark_ = start_;
 return true;
}
ja

void SemiSpace::TearDown() {
 start_ = NULL;
 capacity_ = 0;
}

// 擴(kuò)容
bool SemiSpace::Double() {
 if (!MemoryAllocator::CommitBlock(high(), capacity_)) return false;
 capacity_ *= 2;
 return true;
}

             

SemiSpace他自己不申請內(nèi)存。他是負(fù)責(zé)管理某塊內(nèi)存的,內(nèi)存申請在其他地方處理。

2 NewSpace

NewSpace也是管理新生代內(nèi)存的類。新生代內(nèi)存分為兩半,一個是from區(qū),一個是to區(qū)。具體的作用在分析gc的時候再探討。

   
     
 
    
    

// The young generation space.
//
// The new space consists of a contiguous pair of semispaces.  It simply
// forwards most functions to the appropriate semispace.

class NewSpace : public Malloced {
public:

 NewSpace(int initial_semispace_capacity, int maximum_semispace_capacity);

 bool Setup(Address start, int size);
 void TearDown();

 // True if the space has been set up but not torn down.
  bool HasBeenSetup() {
   return to_space_->HasBeenSetup() && from_space_->HasBeenSetup();
 }

 // Flip the pair of spaces.
 void Flip();

 bool Double();

 bool Contains(Address a) {
   return (reinterpret_cast<uint32_t>(a) & address_mask_)
       == reinterpret_cast<uint32_t>(start_);
 }
 bool Contains(Object* o) {
   return (reinterpret_cast<uint32_t>(o) & object_mask_) == object_expected_;
 }

 // Return the allocated bytes in the active semispace.
 // to區(qū)已分配的內(nèi)存大小
 int Size() { return top() - bottom(); }
 // Return the current capacity of a semispace.
 int Capacity() { return capacity_; }
 // Return the available bytes without growing in the active semispace.
 // to區(qū)還有多少內(nèi)存可用
 int Available() { return Capacity() - Size(); }

 // Return the maximum capacity of a semispace.
 int MaximumCapacity() { return maximum_capacity_; }

 // Return the address of the allocation pointer in the active semispace.
 // 當(dāng)前已經(jīng)分配出去的內(nèi)存的末地址
 Address top() { return allocation_info_.top; }
 // Return the address of the first object in thkeyoctive semispace.
 // to_space的管理的內(nèi)存的首地址
 Address bottom() { return to_space_->low(); }

 // Get the age mark of the inactive semispace.
 Address age_mark() { return from_space_->age_mark(); }
 // Set the age mark in the active semispace.
 void set_age_mark(Address mark) { to_space_->set_age_mark(mark); }

 // The start address of the space and a bit mask. Anding an address in the
 // new space with the mask will result in the start address.
 Address start() { return start_; }
 uint32_t mask() { return address_mask_; }

 // The allocation top and limit addresses.
 // 當(dāng)前已分配的內(nèi)存的末地址
 Address* allocation_top_address() { return &allocation_info_.top; }
 // 最大能分配的內(nèi)存末地址
 Address* allocation_limit_address() { return &allocation_info_.limit; }

 Object* AllocateRaw(int size_in_bytes) {
   return AllocateRawInternal(size_in_bytes, &allocation_info_);
 }

 Object* MCAllocateRaw(int size_in_bytes) {
   return AllocateRawInternal(size_in_bytes, &mc_forwarding_info_);
 }

 void ResetAllocationInfo();

 void MCResetRelocationInfo();

 void MCCommitRelocationInfo();

 // Get the extent of the inactive semispace (for use as a marking stack).
 Address FromSpaceLow() { return from_space_->low(); }
 Address FromSpaceHigh() { return from_space_->high(); }

 // Get the extent of the active semispace (to sweep newly copied objects
 // during a scavenge collection).
 Address ToSpaceLow() { return to_space_->low(); }
 Address ToSpaceHigh() { return to_space_->high(); }

 // Offsets from the beginning of the semispaces.
 int ToSpaceOffsetForAddress(Address a) {
   return to_space_->SpaceOffsetForAddress(a);
 }
 int FromSpaceOffsetForAddress(Address a) {
   return from_space_->SpaceOffsetForAddress(a);
 }

 bool ToSpaceContains(Object* o) { return to_space_->Contains(o); }
 bool FromSpaceContains(Object* o) { return from_space_->Contains(o); }

 bool ToSpaceContains(Address a) { return to_space_->Contains(a); }
 bool FromSpaceContains(Address a) { return from_space_->Contains(a); }

 void RecordAllocation(HeapObject* obj);
 void RecordPromotion(HeapObject* obj);
#endif

private:
 // The current and maximum capacities of a semispace.
 int capacity_;
 int maximum_capacity_;

 // The semispaces.
 SemiSpace* to_space_;
 SemiSpace* from_space_;

 // Start address and bit mask for containment testing.
 Address start_;
 uint32_t address_mask_;
 uint32_t object_mask_;
 uint32_t object_expected_;

 // Allocation pointer and limit for normal allocation and allocation during
 // mark-compact collection.
 AllocationInfo allocation_info_;
 AllocationInfo mc_forwarding_info_;

 // Implementation of AllocateRaw and MCAllocateRaw.
 inline Object* AllocateRawInternal(int size_in_bytes,
                                    AllocationInfo* alloc_info);

 friend class SemiSpaceIterator;

public:
 TRACK_MEMORY("NewSpace")
};

             

newSpace的很多功能但是靠semiSpace來實現(xiàn)的。他負(fù)責(zé)內(nèi)存的具體分配。但不負(fù)責(zé)內(nèi)存的申請。還有些是和gc相關(guān)的功能,后續(xù)再分析。

   
     
 
    
    

// 分為兩個space
NewSpace::NewSpace(int initial_semispace_capacity,
                  int maximum_semispace_capacity) {
 ASSERT(initial_semispace_capacity <= maximum_semispace_capacity);
 ASSERT(IsPowerOf2(maximum_semispace_capacity));
 maximum_capacity_ = maximum_semispace_capacity;
 capacity_ = initial_semispace_capacity;
 to_space_ = new SemiSpace(capacity_, maximum_capacity_);
 from_space_ = new SemiSpace(capacity_, maximum_capacity_);
}

// 設(shè)置需要管理的地址空間,start是首地址,size是大小
bool NewSpace::Setup(Address start, int size) {
 ASSERT(size == 2 * maximum_capacity_);
 ASSERT(IsAddressAligned(start, size, 0));
 // to區(qū)
 if (to_space_ == NULL
     || !to_space_->Setup(start, maximum_capacity_)) {
   return false;
 }
 // from區(qū),和to區(qū)一人一半
 if (from_space_ == NULL
     || !from_space_->Setup(start + maximum_capacity_, maximum_capacity_)) {
   return false;
 }
 // 開始地址
 start_ = start;
 /*
   address_mask的高位是地址的有效位,
   size是只有一位為一,減一后一變成0,一右邊
   的全部0位變成1,然后取反,高位的0變成1,再加上size中本來的1,
   即從左往右的1位地址有效位
 */
 address_mask_ = ~(size - 1);
 // 參考semiSpace的分析
 object_mask_ = address_mask_ | kHeapObjectTag;
 object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag;
 // 初始化管理的地址的信息
 allocation_info_.top = to_space_->low();
 allocation_info_.limit = to_space_->high();
 mc_forwarding_info_.top = NULL;
 mc_forwarding_info_.limit = NULL;

 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
 return true;
}

// 重置屬性,不負(fù)責(zé)內(nèi)存的釋放
void NewSpace::TearDown() {

 start_ = NULL;
 capacity_ = 0;
 allocation_info_.top = NULL;
 allocation_info_.limit = NULL;
 mc_forwarding_info_.top = NULL;
 mc_forwarding_info_.limit = NULL;

 if (to_space_ != NULL) {
   to_space_->TearDown();
   delete to_space_;
   to_space_ = NULL;
 }

 if (from_space_ != NULL) {
   from_space_->TearDown();
   delete from_space_;
   from_space_ = NULL;
 }
}

// 翻轉(zhuǎn),在gc中調(diào)用
void NewSpace::Flip() {
 SemiSpace* tmp = from_space_;
 from_space_ = to_space_;
 to_space_ = tmp;
}

// 擴(kuò)容
bool NewSpace::Double() {
 ASSERT(capacity_ <= maximum_capacity_ / 2);
 // TODO(1240712): Failure to double the from space can result in
 // semispaces of different sizes.  In the event of that failure, the
 // to space doubling should be rolled back before returning false.
 if (!to_space_->Double() || !from_space_->Double()) return false;
 capacity_ *= 2;
 // 從新擴(kuò)容的地址開始分配內(nèi)存,即老內(nèi)存的末端。
 allocation_info_.limit = to_space_->high();
 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
 return true;
}

// 重置管理內(nèi)存分配的指針
void NewSpace::ResetAllocationInfo() {
 allocation_info_.top = to_space_->low();
 allocation_info_.limit = to_space_->high();
 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
}


void NewSpace::MCResetRelocationInfo() {
 mc_forwarding_info_.top = from_space_->low();
 mc_forwarding_info_.limit = from_space_->high();
 ASSERT_SEMISPACE_ALLOCATION_INFO(mc_forwarding_info_, from_space_);
}


void NewSpace::MCCommitRelocationInfo() {
 // Assumes that the spaces have been flipped so that mc_forwarding_info_ is
 // valid allocation info for the to space.
 allocation_info_.top = mc_forwarding_info_.top;
 allocation_info_.limit = to_space_->high();
 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
}

             

我們看到實現(xiàn)里沒有很多具體的邏輯,只是對屬性進(jìn)行操作,或者把操作下發(fā)到semiSpace。下面看一下內(nèi)存分配的函數(shù)。

   
     
 
    
    

// 分配內(nèi)存
Object* NewSpace::AllocateRawInternal(int size_in_bytes,
                                     AllocationInfo* alloc_info) {

 Address new_top = alloc_info->top + size_in_bytes;
 // 內(nèi)存不夠了
 if (new_top > alloc_info->limit) {
   return Failure::RetryAfterGC(size_in_bytes, NEW_SPACE);
 }
 // 地址+低一位的標(biāo)記
 Object* obj = HeapObject::FromAddress(alloc_info->top);
 // 更新指針,指向下一塊可分配的內(nèi)存
 alloc_info->top = new_top;
#ifdef DEBUG
 SemiSpace* space =
     (alloc_info == &allocation_info_) ? to_space_ : from_space_;
 ASSERT(space->low() <= alloc_info->top
        && alloc_info->top <= space->high()
        && alloc_info->limit == space->high());
#endif
 return obj;
}

}

             

內(nèi)存管理,主要是通過開始指針、結(jié)束指針、指向當(dāng)前可分配的內(nèi)存的指針來進(jìn)行管理。每次分配內(nèi)存都會修改當(dāng)前指針的值。

感謝各位的閱讀,以上就是“js引擎SemiSpace怎么實現(xiàn)”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對js引擎SemiSpace怎么實現(xiàn)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI