这篇文章主要讲解了“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")
};
下面是实现
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;
}
ja
void SemiSpace::TearDown() {
start_ = NULL;
capacity_ = 0;
}
// 扩容
bool SemiSpace::Double() {
if (!MemoryAllocator::CommitBlock(high(), capacity_)) return false;
capacity_ *= 2;
return true;
}
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")
};
newSpace的很多功能但是靠semiSpace来实现的。他负责内存的具体分配。但不负责内存的申请。还有些是和gc相关的功能,后续再分析。
// 分为两个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_);
}
// 设置需要管理的地址空间,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_);
}
我们看到实现里没有很多具体的逻辑,只是对属性进行操作,或者把操作下发到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;
}
}
内存管理,主要是通过开始指针、结束指针、指向当前可分配的内存的指针来进行管理。每次分配内存都会修改当前指针的值。
感谢各位的阅读,以上就是“js引擎SemiSpace怎么实现”的内容了,经过本文的学习后,相信大家对js引擎SemiSpace怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
原创文章,作者:745907710,如若转载,请注明出处:https://blog.ytso.com/223324.html