Python的内存管理和垃圾回收机制
内存管理
Python解释器由c语言开发完成,py中所有的操作最终都由底层的c语言来实现并完成,所以想要了解底层内存管理需要结合python源码来进行解释。
1. 两个重要的结构体
include/object.h
#define _PyObject_HEAD_EXTRA \
struct _object *_ob_next; \
struct _object *_ob_prev; #define PyObject_HEAD PyObject ob_base; #define PyObject_VAR_HEAD PyVarObject ob_base; typedef struct _object {
_PyObject_HEAD_EXTRA // 用于构造双向链表
Py_ssize_t ob_refcnt; // 引用计数器
struct _typeobject *ob_type; // 数据类型
} PyObject; typedef struct {
PyObject ob_base; // PyObject对象
Py_ssize_t ob_size; /* Number of items in variable part,即:元素个数 */
} PyVarObject;
以上源码是Python内存管理中的基石,其中包含了:
- 2个结构体
- PyObject,此结构体中包含3个元素。
- _PyObject_HEAD_EXTRA,用于构造双向链表。
- ob_refcnt,引用计数器。
- *ob_type,数据类型。
- PyVarObject,次结构体中包含4个元素(ob_base中包含3个元素)
- ob_base,PyObject结构体对象,即:包含PyObject结构体中的三个元素。
- ob_size,内部元素个数。
- PyObject,此结构体中包含3个元素。
- 3个宏定义
- PyObject_HEAD,代指PyObject结构体。
- PyVarObject_HEAD,代指PyVarObject对象。
- _PyObject_HEAD_EXTRA,代指前后指针,用于构造双向队列。
Python中所有类型创建对象时,底层都是与PyObject和PyVarObject结构体实现,一般情况下由单个元素组成对象内部会使用PyObject结构体(float)、由多个元素组成的对象内部会使用PyVarObject结构体(str/int/list/dict/tuple/set/自定义类),因为由多个元素组成的话是需要为其维护一个 ob_size(内部元素个数)。
typedef struct {
PyObject_HEAD
double ob_fval;
} PyFloatObject;
include/floatobject.h
// longintrepr.h struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
}; // longobject.h /* Long (arbitrary precision) integer object interface */
typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */ /*
1. python3中没有long类型,只有int类型,但py3内部的int是基于long实现。
2. python3中对int/long长度没有限制,因其内部不是用long存储而是使用类似于“字符串”存储。
*/
include/longobject.h
typedef struct {
PyObject_VAR_HEAD
Py_hash_t ob_shash;
char ob_sval[1];
/* Invariants:
* ob_sval contains space for 'ob_size+1' elements.
* ob_sval[ob_size] == 0.
* ob_shash is the hash of the string or -1 if not computed yet.
*/
} PyBytesObject;
include/bytesobject.h
typedef struct {
PyObject_VAR_HEAD /* Vector of pointers to list elements. list[0] is ob_item[0], etc. */
PyObject **ob_item; /* ob_item contains space for 'allocated' elements. The number
* currently in use is ob_size.
* Invariants:
* 0 <= ob_size <= allocated
* len(list) == ob_size
* ob_item == NULL implies ob_size == allocated == 0
* list.sort() temporarily sets allocated to -1 to detect mutations.
*
* Items must normally not be NULL, except during construction when
* the list is not yet visible outside the function that builds it.
*/
Py_ssize_t allocated;
} PyListObject;
include/listobject.h
typedef struct {
PyObject_VAR_HEAD
PyObject *ob_item[1]; /* ob_item contains space for 'ob_size' elements.
* Items must normally not be NULL, except during construction when
* the tuple is not yet visible outside the function that builds it.
*/
} PyTupleObject;
include/tupleobject.h
typedef struct {
PyObject_HEAD
Py_ssize_t ma_used;
PyDictKeysObject *ma_keys;
PyObject **ma_values;
} PyDictObject;
include/dictobject.h
typedef struct {
PyObject_HEAD Py_ssize_t fill; /* Number active and dummy entries*/
Py_ssize_t used; /* Number active entries */ /* The table contains mask + 1 slots, and that's a power of 2.
* We store the mask instead of the size because the mask is more
* frequently needed.
*/
Py_ssize_t mask; /* The table points to a fixed-size smalltable for small tables
* or to additional malloc'ed memory for bigger tables.
* The table pointer is never NULL which saves us from repeated
* runtime null-tests.
*/
setentry *table;
Py_hash_t hash; /* Only used by frozenset objects */
Py_ssize_t finger; /* Search finger for pop() */ setentry smalltable[PySet_MINSIZE];
PyObject *weakreflist; /* List of weak references */
} PySetObject;
include/setobject.h
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ /* Methods to implement standard operations */
... } PyTypeObject; 自定义类 include/object.h
自定义类 include/object.h
注意:Python3只保留int类型,但此时的int就是Python2中的long类型,请看如下官方提示: PEP 0237: Essentially, long
renamed to int
. That is, there is only one built-in integral type, named int
; but it behaves mostly like the old long
type.点击查看原文。
2. 内存管理
以float为例,分析python源码执行流程,了解内存管理机制。
float类型
情景一:创建float对象时
val = 3.14
当按照上述方式创建一个Float类型对象时,源码内部会先后执行如下代码。
/* Special free list
free_list is a singly-linked list of available PyFloatObjects, linked
via abuse of their ob_type members.
*/
static PyFloatObject *free_list = NULL;
static int numfree = 0; PyObject *
PyFloat_FromDouble(double fval)
{
PyFloatObject *op = free_list;
if (op != NULL) {
free_list = (PyFloatObject *) Py_TYPE(op);
numfree--;
} else { // 第一步:根据float类型大小,为float对象开辟内存。
op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));
if (!op)
return PyErr_NoMemory();
} // 第二步:在为float对象开辟的内存中进行初始化。
/* Inline PyObject_New */
(void)PyObject_INIT(op, &PyFloat_Type); // 第三步:将值赋值到float对象开辟的内存中。
op->ob_fval = fval; // 第四步:返回已经创建的float对象的内存地址(引用/指针)
return (PyObject *) op;
}
第一步:根据float类型所需的内存大小,为其开辟内存。
static PyMemAllocatorEx _PyObject = {
#ifdef PYMALLOC_DEBUG
&_PyMem_Debug.obj, PYDBG_FUNCS
#else
NULL, PYOBJ_FUNCS
#endif
}; void *
PyObject_Malloc(size_t size)
{
/* see PyMem_RawMalloc() */
if (size > (size_t)PY_SSIZE_T_MAX)
return NULL; // 开辟内存
return _PyObject.malloc(_PyObject.ctx, size);
} Objects/obmalloc.c
Objects/obmalloc.c
Customize Memory Allocators
=========================== .. versionadded:: 3.4 .. c:type:: PyMemAllocatorEx Structure used to describe a memory block allocator. The structure has
four fields: +----------------------------------------------------------+---------------------------------------+
| Field | Meaning |
+==========================================================+=======================================+
| ``void *ctx`` | user context passed as first argument |
+----------------------------------------------------------+---------------------------------------+
| ``void* malloc(void *ctx, size_t size)`` | allocate a memory block |
+----------------------------------------------------------+---------------------------------------+
| ``void* calloc(void *ctx, size_t nelem, size_t elsize)`` | allocate a memory block initialized |
| | with zeros |
+----------------------------------------------------------+---------------------------------------+
| ``void* realloc(void *ctx, void *ptr, size_t new_size)`` | allocate or resize a memory block |
+----------------------------------------------------------+---------------------------------------+
| ``void free(void *ctx, void *ptr)`` | free a memory block |
+----------------------------------------------------------+---------------------------------------+ .. versionchanged:: 3.5
The :c:type:`PyMemAllocator` structure was renamed to
:c:type:`PyMemAllocatorEx` and a new ``calloc`` field was added. PyMemAllocatorEx的方法说明
PyMemAllocatorEx的方法说明
第二步:对新开辟的内存中进行类型和引用的初始化
/* Head of circular doubly-linked list of all objects. These are linked
* together via the _ob_prev and _ob_next members of a PyObject, which
* exist only in a Py_TRACE_REFS build.
*/
static PyObject refchain = {&refchain, &refchain}; /* Insert op at the front of the list of all objects. If force is true,
* op is added even if _ob_prev and _ob_next are non-NULL already. If
* force is false amd _ob_prev or _ob_next are non-NULL, do nothing.
* force should be true if and only if op points to freshly allocated,
* uninitialized memory, or you've unlinked op from the list and are
* relinking it into the front.
* Note that objects are normally added to the list via _Py_NewReference,
* which is called by PyObject_Init. Not all objects are initialized that
* way, though; exceptions include statically allocated type objects, and
* statically allocated singletons (like Py_True and Py_None).
*/
void
_Py_AddToAllObjects(PyObject *op, int force)
{ if (force || op->_ob_prev == NULL) {
op->_ob_next = refchain._ob_next;
op->_ob_prev = &refchain;
refchain._ob_next->_ob_prev = op;
refchain._ob_next = op;
}
} void
_Py_NewReference(PyObject *op)
{
_Py_INC_REFTOTAL; // 对新开辟的内存中的的引用计数器初始化为1。
op->ob_refcnt = 1; // 将新开辟的内存的指针添加到一个双向链表refchain中。
_Py_AddToAllObjects(op, 1); _Py_INC_TPALLOCS(op);
} Objects/object.c
include/object.c
/* Macros trading binary compatibility for speed. See also pymem.h.
Note that these macros expect non-NULL object pointers.*/
#define PyObject_INIT(op, typeobj) \
( Py_TYPE(op) = (typeobj), _Py_NewReference((PyObject *)(op)), (op) )
include/object.h
所以,float类型每次创建对象时都会把对象放到 refchain 的双向链表中。
情景二:float对象引用时
val = 7.8
data = val
这个过程比较简单,在给对象创建新引用时,会对其引用计数器+1的动作。
/*
The macros Py_INCREF(op) and Py_DECREF(op) are used to increment or decrement
reference counts. Py_DECREF calls the object's deallocator function when
the refcount falls to 0; for
objects that don't contain references to other objects or heap memory
this can be the standard function free(). Both macros can be used
wherever a void expression is allowed. The argument must not be a
NULL pointer. If it may be NULL, use Py_XINCREF/Py_XDECREF instead.
The macro _Py_NewReference(op) initialize reference counts to 1, and
in special builds (Py_REF_DEBUG, Py_TRACE_REFS) performs additional
bookkeeping appropriate to the special build. #define Py_INCREF(op) ( \
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
((PyObject *)(op))->ob_refcnt++) include/object.h
include/object.h
情景三:销毁float对象时
val = 3.14
# 主动删除对象
del val """
主动del删除对象时,会执行对象销毁的动作。
一个函数执行完毕之后,其内部局部变量也会有销毁动作,如:
def func():
val = 2.22 func()
"""
当进行销毁对象动作时,先后会执行如下代码:
The macros Py_INCREF(op) and Py_DECREF(op) are used to increment or decrement
reference counts. Py_DECREF calls the object's deallocator function when
the refcount falls to 0; for
objects that don't contain references to other objects or heap memory
this can be the standard function free(). Both macros can be used
wherever a void expression is allowed. The argument must not be a
NULL pointer. If it may be NULL, use Py_XINCREF/Py_XDECREF instead.
The macro _Py_NewReference(op) initialize reference counts to 1, and
in special builds (Py_REF_DEBUG, Py_TRACE_REFS) performs additional
bookkeeping appropriate to the special build. #define Py_DECREF(op) \
do { \
PyObject *_py_decref_tmp = (PyObject *)(op); \
if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
--(_py_decref_tmp)->ob_refcnt != 0) \
_Py_CHECK_REFCNT(_py_decref_tmp) \
else \
_Py_Dealloc(_py_decref_tmp); \
} while (0) include/object.h
include/object.h
void
_Py_Dealloc(PyObject *op)
{
// 第一步:调用float类型的tp_dealloc,进行内存的销毁
destructor dealloc = Py_TYPE(op)->tp_dealloc; // 第二步:在refchain双向链表中移除
_Py_ForgetReference(op); (*dealloc)(op);
} Objects/object.c
include/object.c
第一步,调用float类型的tp_dealloc进行内存的销毁。
按理此过程说应该直接将对象内存销毁,但float内部有缓存机制,所以他的执行流程是这样的:
- float内部缓存的内存个数已经大于等于100,那么在执行`del val`的语句时,内存中就会直接删除此对象。
- 未达到100时,那么执行 `del val`语句,不会真的在内存中销毁对象,而是将对象放到一个free_list的单链表中,以便以后的对象使用。
/* Special free list
free_list is a singly-linked list of available PyFloatObjects, linked
via abuse of their ob_type members.
*/ #ifndef PyFloat_MAXFREELIST
#define PyFloat_MAXFREELIST 100
#endif
static int numfree = 0;
static PyFloatObject *free_list = NULL; PyTypeObject PyFloat_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"float",
sizeof(PyFloatObject),
0, // tp_dealloc表示执行float_dealloc方法
(destructor)float_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
...
}; static void
float_dealloc(PyFloatObject *op)
{
// 检测是否是float类型
if (PyFloat_CheckExact(op)) { // 检测缓冲池个数是否大于100个
if (numfree >= PyFloat_MAXFREELIST) {
// 如果大于100个,则在内存中销毁对象
PyObject_FREE(op);
return;
}
// 否则,缓冲池个数+1
// 并将要销毁的数据加入到free_list的单项链表中,以便以后创建float类型使用。
numfree++;
Py_TYPE(op) = (struct _typeobject *)free_list;
free_list = op;
}
else
Py_TYPE(op)->tp_free((PyObject *)op);
} Objects/floatobject.c
Objects/floatobject.c
"""
了解Python中float类型的缓存机制之后,就可以理解如下代码的两个内存地址居然一样的现象的本质了。
""" v1 = 3.8
print(id(v1)) # 内存地址:140454027861640
del v1 v2 = 88.7
print(id(v2)) # 内存地址:140454027861640 扩展:读源码了解现象本质
扩展:读源码了解现象本质
void
PyObject_Free(void *ptr)
{
// 与上述开辟内存类似
_PyObject.free(_PyObject.ctx, ptr);
} Objects/obmalloc.c
Objects/obmalloc.c
第二步,在refchain双向链表中移除
/* Head of circular doubly-linked list of all objects. These are linked
* together via the _ob_prev and _ob_next members of a PyObject, which
* exist only in a Py_TRACE_REFS build.
*/
static PyObject refchain = {&refchain, &refchain}; void
_Py_ForgetReference(PyObject *op)
{
#ifdef SLOW_UNREF_CHECK
PyObject *p;
#endif
if (op->ob_refcnt < 0)
Py_FatalError("UNREF negative refcnt");
if (op == &refchain ||
op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) {
fprintf(stderr, "* ob\n");
_PyObject_Dump(op);
fprintf(stderr, "* op->_ob_prev->_ob_next\n");
_PyObject_Dump(op->_ob_prev->_ob_next);
fprintf(stderr, "* op->_ob_next->_ob_prev\n");
_PyObject_Dump(op->_ob_next->_ob_prev);
Py_FatalError("UNREF invalid object");
}
#ifdef SLOW_UNREF_CHECK
for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) {
if (p == op)
break;
}
if (p == &refchain) /* Not found */
Py_FatalError("UNREF unknown object");
#endif
op->_ob_next->_ob_prev = op->_ob_prev;
op->_ob_prev->_ob_next = op->_ob_next;
op->_ob_next = op->_ob_prev = NULL;
_Py_INC_TPFREES(op);
} Objects/object.c
Objects/object.c
综上所述,float对象在创建对象时会把为其开辟内存并初始化引用计数器为1,然后将其加入到名为 refchain 的双向链表中;float对象在增加引用时,会执行 Py_INCREF在内部会让引用计数器+1;最后执行销毁float对象时,会先判断float内部free_list中缓存的个数,如果已达到100个,则直接在内存中销毁,否则不会真正销毁而是加入free_list单链表中,以后后续对象使用,销毁动作的最后再在refchain中移除即可。
垃圾回收机制
Python的垃圾回收机制是以:引用计数器为主,标记清除和分代回收为辅。
1. 引用计数器
每个对象内部都维护了一个值,该值记录这此对象被引用的次数,如果次数为0,则Python垃圾回收机制会自动清除此对象。下图是Python源码中引用计数器存储的代码。
引用计数器的获取及代码示例:
import sys # 在内存中创建一个字符串对象"武沛齐",对象引用计数器的值为:1
nick_name = '武沛齐' # 应该输入2,实际输出2,因为getrefcount方法时把 nick_name 当做参数传递了,引发引用计数器+1,所以打印时值为:2
# 注意:getrefcount 函数执行完毕后,会自动-1,所以本质上引用计数器还是1.
print(sys.getrefcount(nick_name)) # 变量 real_name 也指向的字符串对象"武沛齐",即:引用计数器再 +1,所以值为:2
real_name = nick_name # 应该输出2,实际输出3. 因为getrefcount方法时把 real_name 当做参数传递了,引发引用计数器+1,所以打印时值为:3
# 注意:getrefcount 函数执行完毕后,会自动-1,所以本质上引用计数器还是2.
print(sys.getrefcount(nick_name)) # 删除reald_name变量,并让其指向对象中的引用计数器-1
del real_name # 应该输出1,实际输出2,因为getrefcount方法时把 real_name 当做参数传递了,引发引用计数器+1,所以打印时值为:2.
print(sys.getrefcount(nick_name)) # ############ getrefcount 注释信息 ############
'''
def getrefcount(p_object): # real signature unknown; restored from __doc__
"""
getrefcount(object) -> integer Return the reference count of object. The count returned is generally
one higher than you might expect, because it includes the (temporary)
reference as an argument to getrefcount().
"""
return 0
'''
2. 循环引用
通过引用计数器的方式基本上可以完成Python的垃圾回收,但它还是具有明显的缺陷,即:“循环引用” 。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import gc
import objgraph class Foo(object):
def __init__(self):
self.data = None # 在内存创建两个对象,即:引用计数器值都是1
obj1 = Foo()
obj2 = Foo() # 两个对象循环引用,导致内存中对象的应用+1,即:引用计数器值都是2
obj1.data = obj2
obj2.data = obj1 # 删除变量,并将引用计数器-1。
del obj1
del obj2 # 关闭垃圾回收机制,因为python的垃圾回收机制是:引用计数器、标记清除、分代回收 配合已解决循环引用的问题,关闭他便于之后查询内存中未被释放对象。
gc.disable() # 至此,由于循环引用导致内存中创建的obj1和obj2两个对象引用计数器不为0,无法被垃圾回收机制回收。
# 所以,内存中Foo类的对象就还显示有2个。
print(objgraph.count('Foo'))
注意:gc.collect() 可以主动触发垃圾回收;
循环引用的问题会引发内存中的对象一直无法释放,从而内存逐渐增大,最终导致内存泄露。
为了解决循环引用的问题,Python又在引用计数器的基础上引入了标记清除和分代回收的机制。
so,不必再担心循环引用的问题了。
Reference cycles involving lists, tuples, instances, classes, dictionaries, and functions are found.
Python GC 源码文档:http://www.arctrix.com/nas/python/gc/
3. 标记清除&分代回收
Python为了解决循环引用,针对 lists, tuples, instances, classes, dictionaries, and functions 类型,每创建一个对象都会将对象放到一个双向链表中,每个对象中都有 _ob_next 和 _ob_prev 指针,用于挂靠到链表中。
/* Nothing is actually declared to be a PyObject, but every pointer to
* a Python object can be cast to a PyObject*. This is inheritance built
* by hand. Similarly every pointer to a variable-size Python object can,
* in addition, be cast to PyVarObject*.
*/
typedef struct _object {
_PyObject_HEAD_EXTRA # 双向链表
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject; typedef struct {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject; /* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA \
struct _object *_ob_next; \
struct _object *_ob_prev;
随着对象的创建,该双向链表上的对象会越来越多。
- 当对象个数超过 700个 时,Python解释器就会进行垃圾回收。
- 当代码中主动执行 gc.collect() 命令时,Python解释器就会进行垃圾回收。
import gc gc.collect()
Python解释器在垃圾回收时,会遍历链表中的每个对象,如果存在循环引用,就将存在循环引用的对象的引用计数器 -1,同时Python解释器也会将计数器等于0(可回收)和不等于0(不可回收)的一分为二,把计数器等于0的所有对象进行回收,把计数器不为0的对象放到另外一个双向链表表(即:分代回收的下一代)。
关于分代回收(generations):
The GC classifies objects into three generations depending on how many collection sweeps they have survived. New objects are placed in the youngest generation (generation 0
). If an object survives a collection it is moved into the next older generation. Since generation 2
is the oldest generation, objects in that generation remain there after a collection. In order to decide when to run, the collector keeps track of the number object allocations and deallocations since the last collection. When the number of allocations minus the number of deallocations exceeds threshold0, collection starts. Initially only generation 0
is examined. If generation 0
has been examined more than threshold1 times since generation 1
has been examined, then generation 1
is examined as well. Similarly, threshold2 controls the number of collections of generation 1
before collecting generation 2
.
# 默认情况下三个阈值为 (700,10,10) ,也可以主动去修改默认阈值。
import gc gc.set_threshold(threshold0[, threshold1[, threshold2]])
官方文档: https://docs.python.org/3/library/gc.html
参考文档:
https://www.cnblogs.com/wupeiqi/p/11507404.html
http://www.wklken.me/posts/2015/09/29/python-source-gc.html
https://yq.aliyun.com/users/yqzdoezsuvujg/album?spm=a2c4e.11155435.0.0.d07467451AwRxO
python的数据缓存机制:https://blog.csdn.net/qq_38604355/article/details/97135107
总结:
Python是由C语言开发,操作都是基于C语言实现,Python中创建每个对象,内部都会与C语言结构体委会一些值。
PyObject
上
下
计数器
类型
PyVarObject
PyObject
变量个数
在创建对象时,每个对象内部至少有4个值:双向链表/ob_refcnt/ob_type.之后会对内存中的数据进行初始化,初始化本质:引用计数器=1,赋值,然后将对象添加到双向链表refchain
以后再有其他变量执行这个内存,则让引用计数器+1,如果销毁某个变量,则找到指向的内存,将引用计数器-1,引用计数器如果为0,则进行垃圾回收。
在内部可能存在缓存机制,例如:float/list/int,最开始不会真正销毁,而是放在free_list的链表中,以后再创建同类型的数据时,会先去链表中取出对象,然后再对对象进行初始化。(100/80/5-257)
内存管理机制
- 引用计数器(同上)
- 引用计数器会出现循环引用
a = [1,2]
b = [5,6]
a.append(b) # b的计数器2
b.append(a) # a的计数器2 del a
del b
- 标记清除,针对那些容器类的对象,在Python中会将他们单独放到一个双向链表中做定期扫描,检查是否有循环引用,如果有则-1,如果-1之后等于0,则直接回收。
- 分代回收,为了少扫描对象,将没有问题的对象让它放到上一代链表中,默认下一代扫描10词,上一代才扫描1次,总共有3代。
垃圾回收机制
Python的内存管理和垃圾回收机制的更多相关文章
- python的内存管理与垃圾回收机制学习
一.python内存申请: 1.python的内存管理分为六层:最底的两层有OS控制.第三层是调用C的malloc和free等进行内存控制.第四层第五层是python的内存池.最上层使我们接触的直接对 ...
- JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)
转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...
- JVM内存管理和垃圾回收机制介绍
http://backend.blog.163.com/blog/static/20229412620128233285220/ 内存管理和垃圾回收机制是JVM最核心的两个组成部分,对其内部实 ...
- V8 内存管理和垃圾回收机制总结
这篇文章主要介绍 V8 的内存管理和垃圾回收知识. V8 内存管理及垃圾回收机制浅析 由于 V8 引擎的原因,Node 在操作大内存对象时受到了一些限制,在 64 位的机器上,默认最大操作的对象大小约 ...
- 【第1题】 Pythonn内存管理以及垃圾回收机制
内存管理 Python解释器由c语言开发完成,py中所有的操作最终都由底层的c语言来实现并完成,所以想要了解底层内存管理需要结合python源码来进行解释. 1. 两个重要的结构体 include/o ...
- JVM的生命周期、体系结构、内存管理和垃圾回收机制
一.JVM的生命周期 JVM实例:一个独立运行的java程序,是进程级别 JVM执行引擎:用户运行程序的线程,是JVM实例的一部分 JVM实例的诞生 当启动一个java程序时.一个JVM实例就诞生了, ...
- java基础(一):谈谈java内存管理与垃圾回收机制
看了很多java内存管理的文章或者博客,写的要么笼统,要么划分的不正确,且很多文章都千篇一律.例如部分地方将jvm笼统的分为堆.栈.程序计数器,这么分太过于笼统,无法清晰的阐述java的内存管理模型: ...
- JavaScript 执行环境、作用域、内存管理及垃圾回收机制
前言 JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存. [原理]找出那些不再继续使用的变量,然后释放其占用的内存.为此,垃圾收集器会按照固定的时间间隔( ...
- PHP 内存管理及垃圾回收机制
PHP5的内存管理 对象传递 PHP5使用了Zend引擎II,对象被储存于独立的结构Object Store中,而不像其它一般变量那样储存于Zval中(在PHP4中对象和一般变量一样存储于Zval). ...
随机推荐
- 【JAVA今法修真】 第二章 一气化三清 线程分心念
这是我的微信公众号,希望有兴趣的朋友能够一起交流,也希望能够多多支持新人作者,你的每一份关注都是我写文章的动力:南橘ryc 天有八纪,地分九州,万法仙门与天道剑宗一并坐落在东北方通辽州. 与李小庚想象 ...
- .net core Winform 添加DI和读取配置、添加log
首先新建配置类 public class CaptureOption { /// <summary> /// 是否自启 /// </summary> public bool A ...
- 11、Redis的配置文件
Redis的配置文件 一.Redis配置文件简介 Redis是通过配置文件启动的 Redis对大小写字母不敏感 Redis基本上环境搭建都在配置文件 关于Redis配置文件位置是安装时放的位置,关于R ...
- shell脚本 安全删除MySQL大表
一.简介 源码地址 日期:2018/4/12 介绍:工具用于安全删除MySQL表,对于一些特定场景可能有用 应用场景:大批删除不走索引但是有主键的场景[可以是单列索引,也可是多列索引] 实现思路:根据 ...
- pipeline groovy
目录 一.变量 一.变量 1.直接定义 def x="abc" 2.从脚本执行结果赋值变量 branch = "/jen_script/return-branch.sh ...
- MySQL数据库SUBSTRING_INDEX的运用
一.如何运用SUBSTRING_INDEX截取address的省市区 二.应用SUBSTRING_INDEX函数进行多次嵌套截取 SELECT SUBSTRING_INDEX(t1.`address` ...
- Tableau如何绘制堆叠柱状图
一.将类别,子类别拖拽至列上 二.将度量值拖拽至行上 三.将度量名称拖拽至筛选器上,右键度量名称,编辑筛选器,选择销售额 四.将事先准备的目标销售额拖拽至度量值 五.将度量名称拖拽至标记,分别以颜色和 ...
- ES6解构赋值的简单使用
相较于常规的赋值方式,解构赋值最主要的是'解构'两个字,在赋值的过程中要清晰的知道等号右边的结构. 先简单地看一下原来的赋值方式. var a=[1,2] 分析一下这句代码的几个点: (1)变量申明和 ...
- 2020信息安全铁人三项 pwn复盘
第一赛区 hacknote 程序存在格式化字符串漏洞和uaf,不多说了,很简单. 1 from pwn import * 2 3 p = process('./hacknote') 4 elf = E ...
- [BUUCTF]PWN5——ciscn_2019_n_1
[BUUCTF]PWN5--ciscn_2019_n_1 题目网址:https://buuoj.cn/challenges#ciscn_2019_n_1 步骤: 例行检查,64位,开启了nx保护 nc ...