温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

js引擎SemiSpace怎么实现

发布时间:2021-12-17 09:34:54 阅读:135 作者:iii 栏目:大数据
前端开发者测试专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

这篇文章主要讲解了“js引擎SemiSpace怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“js引擎SemiSpace怎么实现”吧!

1 SemiSpace

SemiSpace是管理新生代内存的类。

   
     
 
    
    // 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是否在该对象管理的内存中,&address_mask即让a减去size-1的大小。如果等于start说明在管理范围内  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).  // 类似上面的逻辑,但是堆对象低位是标记,判断时候需要处理一下,加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函数  uint32_t address_ma函数  uint32_t object_mask_;  uint32_t object_expected_; public:  TRACK_MEMORY("SemiSpace")};
   
     
 
    
    AI代码助手复制代码

下面是实现

   
     
 
    
    SemiSpace::SemiSpace(int initial_capacity, int maximum_capacity)    : capacity_(initial_capacity), maximum_capacity_(maximum_capacity),      start_(NULL), age_mark_(NULL) {}// 设置管理的地址范围bool SemiSpace::Setup(Address start, int size) {  ASSERT(size == maximum_capacity_);  // 判断地址的有效性  if (!MemoryAllocator::CommitBlock(start, capacity_)) return false;  // 管理地址空间的首地址  start_ = start;  // 低于有效范围的掩码,即保证相与后的值小于等于管理的地址范围  address_mask_ = ~(size - 1);  // 计算对象地址掩码,低位是标记位,判断的时候需要保留  object_mask_ = address_mask_ | kHeapObjectTag;  // 见contains函数,对象地址里低位是标记位,判断的时候需要带上  object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag;  // gc相关  age_mark_ = start_;  return true;}javoid SemiSpace::TearDown() {  start_ = NULL;  capacity_ = 0;}// 扩容bool SemiSpace::Double() {  if (!MemoryAllocator::CommitBlock(high(), capacity_)) return false;  capacity_ *= 2;  return true;}
   
     
 
    
    AI代码助手复制代码

SemiSpace他自己不申请内存。他是负责管理某块内存的,内存申请在其他地方处理。

2 NewSpace

NewSpace也是管理新生代内存的类。新生代内存分为两半,一个是from区,一个是to区。具体的作用在分析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区已分配的内存大小  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区还有多少内存可用  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.  // 当前已经分配出去的内存的末地址  Address top() { return allocation_info_.top; }  // Return the address of the first object in thkeyoctive semispace.  // to_space的管理的内存的首地址  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.  // 当前已分配的内存的末地址  Address* allocation_top_address() { return &allocation_info_.top; }  // 最大能分配的内存末地址  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")};
   
     
 
    
    AI代码助手复制代码

newSpace的很多功能但是靠semiSpace来实现的。他负责内存的具体分配。但不负责内存的申请。还有些是和gc相关的功能,后续再分析。

   
     
 
    
    // 分为两个spaceNewSpace::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_);}// 设置需要管理的地址空间,start是首地址,size是大小bool NewSpace::Setup(Address start, int size) {  ASSERT(size == 2 * maximum_capacity_);  ASSERT(IsAddressAligned(start, size, 0));  // to区  if (to_space_ == NULL      || !to_space_->Setup(start, maximum_capacity_)) {    return false;  }  // from区,和to区一人一半  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;}// 重置属性,不负责内存的释放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;  }}// 翻转,在gc中调用void NewSpace::Flip() {  SemiSpace* tmp = from_space_;  from_space_ = to_space_;  to_space_ = tmp;}// 扩容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;  // 从新扩容的地址开始分配内存,即老内存的末端。  allocation_info_.limit = to_space_->high();  ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);  return true;}// 重置管理内存分配的指针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_);}
   
     
 
    
    AI代码助手复制代码

我们看到实现里没有很多具体的逻辑,只是对属性进行操作,或者把操作下发到semiSpace。下面看一下内存分配的函数。

   
     
 
    
    // 分配内存Object* NewSpace::AllocateRawInternal(int size_in_bytes,                                      AllocationInfo* alloc_info) {  Address new_top = alloc_info->top + size_in_bytes;  // 内存不够了  if (new_top > alloc_info->limit) {    return Failure::RetryAfterGC(size_in_bytes, NEW_SPACE);  }  // 地址+低一位的标记  Object* obj = HeapObject::FromAddress(alloc_info->top);  // 更新指针,指向下一块可分配的内存  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;}}
   
     
 
    
    AI代码助手复制代码

内存管理,主要是通过开始指针、结束指针、指向当前可分配的内存的指针来进行管理。每次分配内存都会修改当前指针的值。

感谢各位的阅读,以上就是“js引擎SemiSpace怎么实现”的内容了,经过本文的学习后,相信大家对js引擎SemiSpace怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/u/4217331/blog/4379435

AI

开发者交流群×