常常看到一些編程語言的書上有說,程序運行過程當中,會涉及到 棧(Stack)和 堆(Heap)。尤爲遇到涉及調查內存泄漏的場景時,書本會提醒讓開發人員查看 堆 的狀況javascript
基於上述現象,來了兩個疑問:java
程序執行過程當中,爲何常常會涉及到 棧 和 堆 兩個數據結構,他們一般的做用是什麼?c++
選用 棧 能夠理解,但爲何選用 堆 呢?對比其餘的數據結構,在程序執行過程當中,堆 的優點是什麼?編程
(資料主要來源於 stackoverflow,進行消化以及整理)數據結構
關於 堆棧,首先引入兩個解釋:多線程
根據上述資料可知,上述的兩個疑問提到的 堆 其實都不是對應數據結構中的堆的概念,因此問題自己是不許確的~架構
至於 棧 和 堆 在程序運行過程當中起到什麼樣的做用,詳細過程又是怎麼樣的,上述資料已經能夠窺探一二,而其中的細節,就不是這個篇章能夠容納的了(並且不一樣的系統架構,不一樣的 runtime 細節上又不同),就不在這裏展開細述了。併發
class HeapStats {
public:
static const int kStartMarker = 0xDECADE00;
static const int kEndMarker = 0xDECADE01;
intptr_t* start_marker; // 0
size_t* ro_space_size; // 1
size_t* ro_space_capacity; // 2
size_t* new_space_size; // 3
size_t* new_space_capacity; // 4
size_t* old_space_size; // 5
size_t* old_space_capacity; // 6
size_t* code_space_size; // 7
size_t* code_space_capacity; // 8
size_t* map_space_size; // 9
size_t* map_space_capacity; // 10
size_t* lo_space_size; // 11
size_t* code_lo_space_size; // 12
size_t* global_handle_count; // 13
size_t* weak_global_handle_count; // 14
size_t* pending_global_handle_count; // 15
size_t* near_death_global_handle_count; // 16
size_t* free_global_handle_count; // 17
size_t* memory_allocator_size; // 18
size_t* memory_allocator_capacity; // 19
size_t* malloced_memory; // 20
size_t* malloced_peak_memory; // 21
size_t* objects_per_type; // 22
size_t* size_per_type; // 23
int* os_error; // 24
char* last_few_messages; // 25
char* js_stacktrace; // 26
intptr_t* end_marker; // 27
};
複製代碼
從狀態類上,咱們能夠看到,有針對 新生代 和 老生代 的描述:new_space_size,new_space_capcacity,old_space_size,old_space_capacity,可知 javascript 的堆內存參考過 jvm 的堆內存管理模式,以便優化內存回收的效率app
//
// Most object types in the V8 JavaScript are described in this file.
//
// Inheritance hierarchy:
// - Object
// - Smi (immediate small integer)
// - HeapObject (superclass for everything allocated in the heap)
// - JSReceiver (suitable for property access)
// - JSObject
// - JSArray
// - JSArrayBuffer
// - JSArrayBufferView
// - JSTypedArray
// - JSDataView
// - JSBoundFunction
// - JSCollection
// - JSSet
// - JSMap
// - JSDate
// - JSFunction
// - JSGeneratorObject
// - JSGlobalObject
// - JSGlobalProxy
// - JSMapIterator
// - JSMessageObject
// - JSModuleNamespace
// - JSPrimitiveWrapper
// - JSRegExp
// - JSSetIterator
// - JSStringIterator
// - JSWeakCollection
// - JSWeakMap
// - JSWeakSet
// - JSCollator // If V8_INTL_SUPPORT enabled.
// - JSDateTimeFormat // If V8_INTL_SUPPORT enabled.
// - JSListFormat // If V8_INTL_SUPPORT enabled.
// - JSLocale // If V8_INTL_SUPPORT enabled.
// - JSNumberFormat // If V8_INTL_SUPPORT enabled.
// - JSPluralRules // If V8_INTL_SUPPORT enabled.
// - JSRelativeTimeFormat // If V8_INTL_SUPPORT enabled.
// - JSSegmenter // If V8_INTL_SUPPORT enabled.
// - JSSegmentIterator // If V8_INTL_SUPPORT enabled.
// - JSV8BreakIterator // If V8_INTL_SUPPORT enabled.
// - WasmExceptionObject
// - WasmGlobalObject
// - WasmInstanceObject
// - WasmMemoryObject
// - WasmModuleObject
// - WasmTableObject
// - JSProxy
複製代碼
能夠看到,v8 在執行 js 過程當中,runtime 內部產生的 js 對象會繼承自 HeapObject 這個類,而 HeapObject 會根據策略從 runtime 的 堆 中進行 存儲、移動、釋放等操做jvm
咱們也知道,javascript 的數據類型會區分 基本類型(String,Number,Boolean,Null,Undfined,Symbol) 和 引用數據類型(Object,Array,Function)
從上面的註釋能夠看出來,基本數據類型 並無繼承自 HeapObject,在 js 的執行過程當中,它們會被記錄到 棧(Stack)中,當函數執行完畢後,即從棧中退出。而引用數據類型 則繼承自 HeapObject,在執行過程當中,從堆中存儲,再也不被引用後,將會等待 GC 依據策略將其清理