首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >js引擎v8源码分析之NewSpace(基于v8 0.1.5)

js引擎v8源码分析之NewSpace(基于v8 0.1.5)

作者头像
theanarkh
发布2020-02-17 11:49:28
7300
发布2020-02-17 11:49:28
举报
文章被收录于专栏:原创分享原创分享

NewSpace是v8内存管理中,负责管理新生代区的类。分为from和to两个区,每个区由SemiSpace对象管理。和SemiSpace一样,NewSpace也不负责内存的分配和释放,他只负责内存的使用和管理。下面是类的定义。

class NewSpace : public Malloced {
 public:
  NewSpace(int initial_semispace_capacity, int maximum_semispace_capacity);

  bool Setup(Address start, int size);

  void TearDown();

  bool HasBeenSetup() {
    return to_space_->HasBeenSetup() && from_space_->HasBeenSetup();
  }

  void Flip();

  bool Double();
  // 判断地址a是否属于NewSpace管理的内存范围,address_mask_是用于清除a的低n位。见SetUp函数
  bool Contains(Address a) {
    return (reinterpret_cast<uint32_t>(a) & address_mask_)
        == reinterpret_cast<uint32_t>(start_);
  }
  // 判断堆对象是不是在NewSpace管理的内存里,object_mask_和object_expected_见SetUp函数
  bool Contains(Object* o) {
    return (reinterpret_cast<uint32_t>(o) & object_mask_) == object_expected_;
  }

  // to区已分配的内存大小
  int Size() { return top() - bottom(); }

  int Capacity() { return capacity_; }

  // to区还有多少内存可用
  int Available() { return Capacity() - Size(); }

  int MaximumCapacity() { return maximum_capacity_; }

  // 当前已经分配出去的内存的末地址
  Address top() { return allocation_info_.top; }
  // to_space的管理的内存的首地址
  Address bottom() { return to_space_->low(); }

  Address age_mark() { return from_space_->age_mark(); }

  void set_age_mark(Address mark) { to_space_->set_age_mark(mark); }

  Address start() { return start_; }
  uint32_t mask() { return address_mask_; }

  // 当前已分配的内存的末地址
  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();

  Address FromSpaceLow() { return from_space_->low(); }
  Address FromSpaceHigh() { return from_space_->high(); }
  // to区管理的内存的首地址和末地址
  Address ToSpaceLow() { return to_space_->low(); }
  Address ToSpaceHigh() { return to_space_->high(); }
  // 地址a距离to区管理的内存的首地址的偏移
  int ToSpaceOffsetForAddress(Address a) {
    return to_space_->SpaceOffsetForAddress(a);
  }
  int FromSpaceOffsetForAddress(Address a) {
    return from_space_->SpaceOffsetForAddress(a);
  }
  // 见SemiSpace
  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); }

 private:
  int capacity_;
  int maximum_capacity_;

  SemiSpace* to_space_;
  SemiSpace* from_space_;

  Address start_;
  uint32_t address_mask_;
  uint32_t object_mask_;
  uint32_t object_expected_;
  /*
    struct AllocationInfo {
      Address top;  // current allocation top
      Address limit;  // current allocation limit
    };
  */
  AllocationInfo allocation_info_;
  AllocationInfo mc_forwarding_info_;

  inline Object* AllocateRawInternal(int size_in_bytes,
                                     AllocationInfo* alloc_info);

  friend class SemiSpaceIterator;

 public:
  TRACK_MEMORY("NewSpace")
};

下面看看类的实现。

NewSpace

一个NewSpace分为两个SemiSpace,真正的初始化函数是SetUp

// 分为两个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_);
}

Setup

初始化NewSpace对象的属性。和from区to区。

// 设置需要管理的地址空间,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);
  // 用于判断堆对象是不是在NewSpace管理的内存范围
  object_mask_ = address_mask_ | kHeapObjectTag;
  object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag;
  // 初始化管理的地址的信息,to区管理的开始地址和结束地址
  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;
}

TearDown

重置属性,不负责内存的释放

// 重置属性,不负责内存的释放
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();
    // 释放SemiSpace对象
    delete to_space_;
    to_space_ = NULL;
  }

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

Flip

翻转from区和to区。

// 翻转,在gc中调用
void NewSpace::Flip() {
  SemiSpace* tmp = from_space_;
  from_space_ = to_space_;
  to_space_ = tmp;
}

Double

// 扩容
bool NewSpace::Double() {
  ASSERT(capacity_ <= maximum_capacity_ / 2);
  if (!to_space_->Double() || !from_space_->Double()) return false;
  capacity_ *= 2;
  // 从新扩容的地址开始分配内存,即之前分配的内存的末端。
  allocation_info_.limit = to_space_->high();
  return true;
}

还有一些重置属性的函数。在垃圾回收的时候再具体分析他的作用。

// 重置管理内存分配的指针
void NewSpace::ResetAllocationInfo() {
  allocation_info_.top = to_space_->low();
  allocation_info_.limit = to_space_->high();
}

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


void NewSpace::MCCommitRelocationInfo() {

  allocation_info_.top = mc_forwarding_info_.top;
  allocation_info_.limit = to_space_->high();
}

AllocateRawInternal

// 分配内存
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);
  }
  // 地址+低一位的标记,转成堆对象的地址表示,即低位置1
  Object* obj = HeapObject::FromAddress(alloc_info->top);
  // 更新指针,指向下一块可分配的内存
  alloc_info->top = new_top;
  return obj;
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NewSpace
  • Setup
  • TearDown
  • Flip
  • Double
  • AllocateRawInternal
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档