您好,登錄后才能下訂單哦!
這篇文章主要講解了“js引擎zone怎么使用”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“js引擎zone怎么使用”吧!
zone也是用于內(nèi)存管理的,不過他是增量分配,一次銷毀的。下面是結(jié)構(gòu)圖。
zone.h
#ifndef V8_ZONE_H_
#define V8_ZONE_H_
namespace v8 { namespace internal {
// The Zone supports very fast allocation of small chunks of
// memory. The chunks cannot be deallocated individually, but instead
// the Zone supports deallocating all chunks in one fast
// operation. The Zone is used to hold temporary data structures like
// the abstract syntax tree, which is deallocated after compilation.
// Note: There is no need to initialize the Zone; the first time an
// allocation is attempted, a segment of memory will be requested
// through a call to malloc().
// Note: The implementation is inherently not thread safe. Do not use
// from multi-threaded code.
class Zone {
public:
// Allocate 'size' bytes of memory in the Zone; expands the Zone by
// allocating new segments of memory on demand using malloc().
// 分配size大小的內(nèi)存
static inline void* New(int size);
// Delete all objects and free all memory allocated in the Zone.
// 一次性釋放所有內(nèi)存
static void DeleteAll();
private:
// All pointers returned from New() have this alignment.
static const int kAlignment = kPointerSize;
// Never allocate segments smaller than this size in bytes.
static const int kMinimumSegmentSize = 8 * KB;
// Never keep segments larger than this size in bytes around.
static const int kMaximumKeptSegmentSize = 64 * KB;
// The Zone is intentionally a singleton; you should not try to
// allocate instances of the class.
// 不能new 只能調(diào)用Zone::New
Zone() { UNREACHABLE(); }
// Expand the Zone to hold at least 'size' more bytes and allocate
// the bytes. Returns the address of the newly allocated chunk of
// memory in the Zone. Should only be called if there isn't enough
// room in the Zone already.
// 擴展內(nèi)存
static Address NewExpand(int size);
// The free region in the current (front) segment is represented as
// the half-open interval [position, limit). The 'position' variable
// is guaranteed to be aligned as dictated by kAlignment.
// 管理內(nèi)存的首地址和大小限制
static Address position_;
static Address limit_;
};
// ZoneObject is an abstraction that helps define classes of objects
// allocated in the Zone. Use it as a base class; see ast.h.
// 對Zone的封裝new ZoneObject();即Zone::New(size);
class ZoneObject {
public:
// Allocate a new ZoneObject of 'size' bytes in the Zone.
void* operator new(size_t size) { return Zone::New(size); }
// Ideally, the delete operator should be private instead of
// public, but unfortuately the compiler sometimes synthesizes
// (unused) destructors for classes derived from ZoneObject, which
// require the operator to be visible. MSVC requires the delete
// operator to be public.
// ZoneObjects should never be deleted individually; use
// Zone::DeleteAll() to delete all zone objects in one go.
// 禁止delete該類的對象
void operator delete(void*, size_t) { UNREACHABLE(); }
};
/*
管理allow_allocation_字段,
new AssertNoZoneAllocation的時候,保存當(dāng)前的allow_allocation_,
設(shè)置allow_allocation_為false,析構(gòu)后,恢復(fù)allow_allocation_的值
*/
class AssertNoZoneAllocation {
public:
AssertNoZoneAllocation() : prev_(allow_allocation_) {
allow_allocation_ = false;
}
~AssertNoZoneAllocation() { allow_allocation_ = prev_; }
static bool allow_allocation() { return allow_allocation_; }
private:
bool prev_;
static bool allow_allocation_;
};
// The ZoneListAllocationPolicy is used to specialize the GenericList
// implementation to allocate ZoneLists and their elements in the
// Zone.
class ZoneListAllocationPolicy {
public:
// Allocate 'size' bytes of memory in the zone.
static void* New(int size) { return Zone::New(size); }
// De-allocation attempts are silently ignored.
static void Delete(void* p) { }
};
// ZoneLists are growable lists with constant-time access to the
// elements. The list itself and all its elements are allocated in the
// Zone. ZoneLists cannot be deleted individually; you can delete all
// objects in the Zone by calling Zone::DeleteAll().
template<typename T>
// ZoneList本質(zhì)上是一個list,ZoneListAllocationPolicy是list里的內(nèi)存管理器
class ZoneList: public List<T, ZoneListAllocationPolicy> {
public:
// Construct a new ZoneList with the given capacity; the length is
// always zero. The capacity must be non-negative.
explicit ZoneList(int capacity)
: List<T, ZoneListAllocationPolicy>(capacity) { }
};
} } // namespace v8::internal
#endif // V8_ZONE_H_
zone-inl.h
#ifndef V8_ZONE_INL_H_
#define V8_ZONE_INL_H_
#include "zone.h"
namespace v8 { namespace internal {
inline void* Zone::New(int size) {
ASSERT(AssertNoZoneAllocation::allow_allocation());
// Round up the requested size to fit the alignment.
size = RoundUp(size, kAlignment);
// Check if the requested size is available without expanding.
// 當(dāng)前的指針位置
Address result = position_;
/*
一開始position和limit都是0,所以會分配一個segment,后續(xù)還需要分配的時候,如果segment
里的內(nèi)存還可以滿足,則不需要再分配一個新的segment,在原來的分配就行,
分配size后超過了限制,擴容的時候也是分配一個segment
*/
if ((position_ += size) > limit_) result = NewExpand(size);
// Check that the result has the proper alignment and return it.
ASSERT(IsAddressAligned(result, kAlignment, 0));
return reinterpret_cast<void*>(result);
}
} } // namespace v8::internal
#endif // V8_ZONE_INL_H_
zone.cc
#include "v8.h"
#include "zone-inl.h"
namespace v8 { namespace internal {
Address Zone::position_ = 0;
Address Zone::limit_ = 0;
bool AssertNoZoneAllocation::allow_allocation_ = true;
// Segments represent chunks of memory: They have starting address
// (encoded in the this pointer) and a size in bytes. Segments are
// chained together forming a LIFO structure with the newest segment
// available as Segment::head(). Segments are allocated using malloc()
// and de-allocated using free().
class Segment {
public:
// 下一個節(jié)點
Segment* next() const { return next_; }
// 斷開指向下一個節(jié)點的指針
void clear_next() { next_ = NULL; }
// 內(nèi)存總大小
int size() const { return size_; }
// 內(nèi)存可用大小,前面有一個Segment對象
int capacity() const { return size_ - sizeof(Segment); }
// 內(nèi)存的開始地址,即Segement對象
Address start() const { return address(sizeof(Segment)); }
// 結(jié)束地址即首地址加上size
Address end() const { return address(size_); }
// 返回第一個Segment節(jié)點
static Segment* head() { return head_; }
static void set_head(Segment* head) { head_ = head; }
// Creates a new segment, sets it size, and pushes it to the front
// of the segment chain. Returns the new segment.
// 新增一個Segment
static Segment* New(int size) {
Segment* result = reinterpret_cast<Segment*>(Malloced::New(size));
// 分配成功
if (result != NULL) {
// 頭插入插入鏈表,size是分配的總大小
result->next_ = head_;
result->size_ = size;
head_ = result;
}
return result;
}
// Deletes the given segment. Does not touch the segment chain.
// 釋放segment節(jié)點
static void Delete(Segment* segment) {
Malloced::Delete(segment);
}
private:
// Computes the address of the nth byte in this segment.
// 首地址加上n個字節(jié)
Address address(int n) const {
return Address(this) + n;
}
// 管理所有segment節(jié)點的頭指針
static Segment* head_;
// 每個segment節(jié)點的屬性
Segment* next_;
int size_;
};
Segment* Segment::head_ = NULL;
void Zone::DeleteAll() {
#ifdef DEBUG
// Constant byte value used for zapping dead memory in debug mode.
static const unsigned char kZapDeadByte = 0xcd;
#endif
// Find a segment with a suitable size to keep around.
Segment* keep = Segment::head();
// 到末節(jié)點或者小于kMaximumKeptSegmentSize大小的節(jié)點
while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) {
keep = keep->next();
}
// Traverse the chained list of segments, zapping (in debug mode)
// and freeing every segment except the one we wish to keep.
Segment* current = Segment::head();
// 處理keep節(jié)點,其余節(jié)點的內(nèi)存都被釋放
while (current != NULL) {
Segment* next = current->next();
if (current == keep) {
// Unlink the segment we wish to keep from the list.
current->clear_next();
} else {
#ifdef DEBUG
// Zap the entire current segment (including the header).
memset(current, kZapDeadByte, current->size());
#endif
Segment::Delete(current);
}
current = next;
}
// If we have found a segment we want to keep, we must recompute the
// variables 'position' and 'limit' to prepare for future allocate
// attempts. Otherwise, we must clear the position and limit to
// force a new segment to be allocated on demand.
// 更新屬性,有保留的內(nèi)存則用于下次分配
if (keep != NULL) {
Address start = keep->start();
position_ = RoundUp(start, kAlignment);
limit_ = keep->end();
#ifdef DEBUG
// Zap the contents of the kept segment (but not the header).
memset(start, kZapDeadByte, keep->capacity());
#endif
} else {
position_ = limit_ = 0;
}
// Update the head segment to be the kept segment (if any).
// 更新頭指針
Segment::set_head(keep);
}
Address Zone::NewExpand(int size) {
// Make sure the requested size is already properly aligned and that
// there isn't enough room in the Zone to satisfy the request.
ASSERT(size == RoundDown(size, kAlignment));
ASSERT(position_ + size > limit_);
// Compute the new segment size. We use a 'high water mark'
// strategy, where we increase the segment size every time we expand
// except that we employ a maximum segment size when we delete. This
// is to avoid excessive malloc() and free() overhead.
Segment* head = Segment::head();
int old_size = (head == NULL) ? 0 : head->size();
int new_size = sizeof(Segment) + kAlignment + size + (old_size << 1);
if (new_size < kMinimumSegmentSize) new_size = kMinimumSegmentSize;
// 分配一個新的segment節(jié)點插入到鏈表
Segment* segment = Segment::New(new_size);
if (segment == NULL) V8::FatalProcessOutOfMemory("Zone");
// Recompute 'top' and 'limit' based on the new segment.
Address result = RoundUp(segment->start(), kAlignment);
// 更新屬性,下次分配的時候使用
position_ = result + size;
limit_ = segment->end();
ASSERT(position_ <= limit_);
return result;
}
} } // namespace v8::internal
感謝各位的閱讀,以上就是“js引擎zone怎么使用”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對js引擎zone怎么使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。