`
Joard
  • 浏览: 28565 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

云风manualgc源码注解

阅读更多
这是08年8月的老东西了,当时把云风的manualgc的源码打印出来,没事找时间看看,把自己的理解或注解随手写在源码旁边。今天贴这里以此与各位研究过云风GC的朋友交流。不论如何研究这个gc对我这个长期使用java的programmer来说收获良多。
/*
* Copyright (c) 2008 ,
* Cloud Wu . All rights reserved.
*
* http://www.codingnow.com
*
* Use, modification and distribution are subject to the "New BSD License"
* as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
*/

#include "gc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#ifdef _MSC_VER
#define bool int
#define true 1
#define false 0
typedef int intptr_t;
#else
#include <stdbool.h>
#include <stdint.h>
#endif
#define my_malloc malloc
#define my_free free
#define my_realloc realloc

#define CACHE_BITS 10

struct link {
int number;        该link的children数量
int children[1];
};

struct node {
int mark;     标记值,用于垃圾回收
union {
struct {
void * mem;     该node所指向的内存块
struct link *children;     该node的link关系
void (*finalizer)(void *);
} n;

struct {
intptr_t mem;
struct link *children;
intptr_t weak;
} c;
    在这里通过union把n与c描述的同一种事物解释成两种不同的东西

int free;     记录下个free node在pool中的句柄位置
} u;
};

/* stack data
+----------+
0 | level 0 | ----> level 0 / root ( node pack )
1 | level 1 | --+-> level 1 ( 1 node ref + node pack )
2 | node ref | <-bottom --+
3 | 2 (lv.2) |
4 | node ref | --+-> level 2 ( 3 node ref )
5 | node ref | |
6 | node ref | --+
7 | 4 (lv.3) | <-current
8 | node ref | --+-> level 3 ( 2 node ref )
9 | node ref | --+
10| nil | <-top
11| nil |
+----------+
*/

union stack_node {
int stack;     堆栈挂接点所引用的pool中的句柄
int number;     距上一个堆栈调挂接点的偏移量
int handle;     句柄,pool中的句柄位置
};

struct stack {
union stack_node *data;
int top;
int bottom;
int current;
};

top代表栈顶,data[top]指向nil或者无效值;

bottom代表当前stack frame的栈底。data[bottom-1].stack指向当前stack frame的堆栈挂接点;而如果存在的话data[bottom-2].stack指向上一级堆栈挂接点,并且两者直接必然存在link;stack frame是由gc_enter创建的;

当current>bottom时,data[current].number代表当前堆栈挂接点据上一个堆栈挂接点的偏移量,而当current<bottom时,data[current].stack同data[bottom-1].stack。


struct hash_node {
int id;     pool中的句柄
struct hash_node *next;     表示下一个hash node,用于当hashcode冲突时,将具有相同hashcode的node形成一个链表,一旦hashcode冲突就执行线性查找。
};

struct hash_map {
struct hash_node **table;
int size;     hashmap的大小
struct hash_node *free;     分配出来的hash_node经map_erase释放的后加入free链表以备重用
int number;     当前hashmap的使用数目
};

在这个hashmap的实现中并没有显示使用装载因子,默认装载因子为1,即完全使用晚所有的hashnode后再扩展大小。

#define CACHE_SIZE (1<<CACHE_BITS)

struct cache_node {
int parent;
int child;
};

static struct {
struct node *pool;
int size;     pool的大小
int free;     第一个free node的句柄
int mark;     当前gc的标识值
bool cache_dirty;
struct stack stack;
struct hash_map map;     加速访问pool,将无论地址映射成为pool中的句柄
struct cache_node cache[CACHE_SIZE];     缓存link关系
} E;

#define WEAK_CONTAINER -1
#define FREED_POINTER -1
#define CACHE_PARENT_BITS (CACHE_BITS/3)
#define CACHE_CHILD_BITS (CACHE_BITS-CACHE_PARENT_BITS)
#define CACHE_PARENT_MASK ((1<<CACHE_PARENT_BITS) -1 )
#define CACHE_CHILD_MASK ((1<<CACHE_CHILD_BITS) -1 )
#define UNSET_MASK 0x80000000
#define UNSET_MASK_BIT(a) ((unsigned)(a)>>31)

/* Insert a parent/child handle pair into cache */
添加或者删除一个缓存中的link关系。由于pool的句柄必是正整数,因此使用符号位来标识是执行删除操作。在后续中多次用到这个“符号位”。

static bool
cache_insert(int parent,int child)
{
int hash = (parent & CACHE_PARENT_MASK) << CACHE_CHILD_BITS | (child & CACHE_CHILD_MASK) ;
struct cache_node *cn = &E.cache[hash];
E.cache_dirty=true;

if (cn->parent == -1) {     不存在则添加该link的缓存
cn->parent=parent;
cn->child=child;
return true;
}
else if (cn->parent == parent && (cn->child ^ child) == UNSET_MASK) {
删除已缓存的link
cn->parent = -1;
return true;
}
return false;     该cache已被使用
}

/* create a new handle for pointer p */
从pool中分配一个handle

static int
node_alloc(void *p)
{
struct node *ret;     指向E.free所表示的可重用的free node
if (E.free==-1) {     与后面的E.pool[sz-1].u.free=-1相呼,应标识pool已用尽
int sz=E.size * 2;
int i;
if (sz==0) {
sz=1024;
}

E.pool=(struct node *)my_realloc(E.pool,sz*sizeof(struct node));
ret=E.pool + E.size;
ret->u.n.children=0;

for (i=E.size+1;i<sz;i++) {
E.pool[i].u.free=i+1;     下个free node的句柄位置
E.pool[i].mark=-1;
E.pool[i].u.n.children=0;
}
E.pool[sz-1].u.free=-1;
E.free=E.size+1;
E.size=sz;
}
else {
ret=E.pool + E.free;
E.free = E.pool[E.free].u.free;     将下一个free node的句柄告诉给E.free
}
ret->u.n.mem=p;
ret->mark=0;
if (ret->u.n.children) {
ret->u.n.children->number=0;
}
else {
ret->u.n.children=0;
}
return ret-E.pool;
}

/* expand link table space . each node has a link table. */
来来来,肉戏开始了。直接引用云风的原话
“利用二进制逻辑运算的性质,我们只需要把新的尺寸和老的尺寸异或,再和老的尺寸比较,就可以知道,新的尺寸的二进制最高是 1 的那一位的位置是否大于老的尺寸。然后分配新尺寸的两倍,空间是绰绰有余的。”

static struct link *
link_expand(struct link *old,int sz)
{
struct link *ret;
if (old!=0) {
sz+=old->number;
if ((sz ^ old->number) <= old->number) {
return old;
}
}

sz=sz*2-1;
ret=(struct link *)my_realloc(old,sizeof(struct link)+(sz-1)*sizeof(int));
if (old==0) {
ret->number=0;
}
return ret;
}

/* cmp function for cache sort */
static int
cache_node_cmp(const void *a,const void *b)
{
const struct cache_node *ca=(const struct cache_node *)a;
const struct cache_node *cb=(const struct cache_node *)b;
if (ca->parent != cb->parent) {
return cb->parent - ca->parent;     按parent的降序排列
}
if (ca->parent == -1 ) {
return 0;
}
return (ca->child & ~ UNSET_MASK) - (cb->child & ~UNSET_MASK);
    当parent相同时,按child的升序排列
}

/* commit cache to the node graph *
static void
cache_flush()
{
int i;
if (!E.cache_dirty)
return;
qsort(E.cache,CACHE_SIZE,sizeof(struct cache_node),cache_node_cmp);     快排
i=0;
while (i<CACHE_SIZE) {
int parent=E.cache[i].parent;
struct cache_node *head;
struct cache_node *next;
struct node *node=&E.pool[parent];
struct link *children;
int sz;
int j,k;

if (parent==-1) {
return;
}

head=&E.cache[i];
next=head;
sz=0;

寻找需要对link进行扩展的理论上的最大值,后面会更具情况减少
while (next->parent == parent && i<CACHE_SIZE) {
sz += 1 - UNSET_MASK_BIT(next->child);
++next;
++i;
}

children=node->u.n.children;
k=j=0;
if (children) {
while (j<children->number) {
int child;
if (head>=next) {
goto copy_next;
}

child=head->child;
children->children[k]=children->children[j];
if (child == (children->children[j] | UNSET_MASK)) {
 取消link关系
--k;     与后面的k++对应,已达到k不增长
head->parent=-1;
--sz;
++head;
}
else if ((child & ~UNSET_MASK) < children->children[j]) {
break;
}     需要添加link且小于当前child,维护有序children
++j;
++k;
}
}
if (sz>0) {
    扩展sz个位置
children=node->u.n.children=link_expand(node->u.n.children,sz);
assert(children);
memmove(children->children + j + sz, children->children +j , (children->number - j) * sizeof(int));
j+=sz;
children->number+=sz;
}

while(j<children->number) {
int child;
if (head>=next) {     cache里的值已经全部处理了
goto copy_next;
}

child=head->child;
if (child == (children->children[j] | UNSET_MASK)) {     取消link
--k;
head->parent=-1;
++head;
}
else if ((child & ~UNSET_MASK) < children->children[j]) {
设置新的link
assert(child >= 0 );
children->children[k]=child;
head->parent=-1;
++head;
--j;
}
else {     复制原有的link关系
children->children[k]=children->children[j];
}
++j;
++k;
}
while(head<next) {     添加剩下的值
int child=head->child;
assert((child & UNSET_MASK) == 0);
children->children[k]=child;
++k;
head->parent=-1;
++head;
}
children->number=k;
continue;
copy_next:
if (k!=j) {
for (;j<children->number;j++,k++) {
children->children[k]=children->children[j];
}
children->number=k;
}
}

E.cache_dirty=false;
}

/* add an edge into (or delete from) graph */

static void
node_add(int parent,int child)
{
while (!cache_insert(parent,child)) {     当cache插入失败时继续插入
cache_flush();
}
}

/* free a node for reuse */
释放一个node并加入free node中

static __inline void
node_free(int id)
{
E.pool[id].mark=-1;
if (E.pool[id].u.n.children) {
E.pool[id].u.n.children->number=0;
}
E.pool[id].u.free=E.free;
E.free=id;
}

/* create a hash value for pointer p */

static __inline int
hash(void *p)
{
intptr_t t=(intptr_t)p;
return (int)((t>>2) ^ (t>>16));
}

/* expand hash map space */

static void
map_expand()
{
struct hash_node **table;
int sz,i;
if (E.map.size==0) {
sz=1024;
}
else {
sz=E.map.size*2;
}
table=(struct hash_node **)my_malloc(sz*sizeof(struct hash_node *));
memset(table,0,sz*sizeof(struct hash_node *));
重新hash
for (i=0;i<E.map.size;i++) {
struct hash_node *t=E.map.table[i];
while (t) {
struct hash_node *tmp=t;
void *p=E.pool[tmp->id].u.n.mem;
int new_hash=hash(p) & (sz-1);
t=t->next;

tmp->next=table[new_hash];
table[new_hash]=tmp;
}
}

my_free(E.map.table);
E.map.table=table;
E.map.size=sz;
}

/* map a existed pointer into a handle , if not exist, create a new one */
把一个物理地址映射成为pool中的句柄

static int
map_id(void *p)
{
int h=hash(p);
求在hashmap中的位置,确保其在size内

struct hash_node *node=E.map.table[h & (E.map.size -1)];
while (node) {
if (E.pool[node->id].u.n.mem==p) {
return node->id;
}
node=node->next;
}

if (E.map.number >= E.map.size) {
map_expand();
}

++E.map.number;

if (E.map.free) {
node=E.map.free;
E.map.free=node->next;
}
else {
node=(struct hash_node *)my_malloc(sizeof(*node));
}
node->id=node_alloc(p);
node->next=E.map.table[h & (E.map.size -1)];
E.map.table[h & (E.map.size -1)]=node;

return node->id;
}

/* Erase a handle from hash map */

static void
map_erase(int id)
{
void *p=E.pool[id].u.n.mem;
if (p) {
int h=hash(p);
struct hash_node **node= &E.map.table[h & (E.map.size -1)];
struct hash_node *find;
while ((*node)->id!=id) {     当hashcode冲突时查找转为线性查找链表
node=&(*node)->next;
assert(*node);
}
    将查找到的hash_node加入free链表以备重用

find=*node;
*node=find->next;
find->next=E.map.free;
E.map.free=find;
--E.map.number;
}
}

/* Expand stack space */
    __inline 函数内联,一些编译器才有,如gcc。在C99中可以直接使用inline

static __inline void
stack_expand()
{
只有当top为2^n – 1时才会进行扩展
if (((E.stack.top + 1) ^ E.stack.top) > E.stack.top) {
E.stack.data = (union stack_node *)my_realloc(E.stack.data,(E.stack.top*2+1) * sizeof(union stack_node));
分配2^(n+1) -1个stack node
}
}

/* Push a handle into the stack */

static void
stack_push(int handle)
{
stack_expand();
E.stack.data[E.stack.top++].handle=handle;
}

/* gc brackets open */

void
gc_enter()
{
stack_expand();
设置新的堆栈挂接点
E.stack.data[E.stack.top].number=E.stack.top-E.stack.current;
E.stack.current=E.stack.top++;
}

/* gc brackets close , extend some pointers' lifetime */
可变参数必须以0结尾

void
gc_leave(void *p,...)
{
void **head;
if (E.stack.current >= E.stack.bottom) {     直接取消该堆栈挂接点,因为此时还未执行stach_pack所以,挂靠在该堆栈挂接点上的所有内存都不会有任何link存在,可以被回收掉。

E.stack.top = E.stack.current;
E.stack.current -= E.stack.data[E.stack.current].number;
}
else {     leave前执行了stack_pack(包括gc_collect的间接调用)
int parent,child;
--E.stack.bottom;
parent=E.stack.data[E.stack.bottom-1].stack;
child=E.stack.data[E.stack.bottom].stack;
node_add(parent, child | UNSET_MASK);     取消该堆栈挂接点与上一级的link
node_free(child);
E.stack.current=E.stack.bottom-1;     恢复到上一级堆栈挂接点
E.stack.top = E.stack.current + 1;
}

head=&p;

while (*head) {     将程序显示要求的保留的内存压栈,以延长起生命周期
stack_push(map_id(*head));
++head;
}
}

/* pack the stack recursively */

static int
stack_pack_internal(int from,int to,int top)
{
if (to < from) {     将to…from内的句柄(内存)与这一级堆栈挂接点建立link关系
int parent = E.stack.data[to].stack;
while (from < top) {
node_add(parent,E.stack.data[from].handle);
++from;
}
return to+1;
}
else {
递归处理上一级堆栈挂点

int bottom=stack_pack_internal(from,to-E.stack.data[to].number,to);
将(to+1)…top内的内存与node建立link关系
int node=node_alloc(0);
++to;
while (to<top) {
node_add(node,E.stack.data[to].handle);
++to;
}
node_add(E.stack.data[bottom-1].stack,node);     挂靠node
E.stack.data[bottom].stack=node;
return bottom+1;
}
}

/* pack the value in the stack */

static void
stack_pack()
{
int bottom=stack_pack_internal(E.stack.bottom,E.stack.current,E.stack.top);
E.stack.top=E.stack.bottom=bottom;
E.stack.current=bottom-1;
}

/* link or unlink two pointer */
建立parent/now的link关系
取消parent/prev的link关系

void
gc_link(void *parent,void *prev,void *now)
{
int parent_id;
if (parent==0) {
parent_id=0;
}
else {
parent_id=map_id(parent);
}
if (prev) {
int prev_id=map_id(prev);
stack_push(prev_id);
node_add(parent_id,prev_id | UNSET_MASK);
}
if (now) {
node_add(parent_id,map_id(now));
}
}

/* init struct E */

void
gc_init()
{
int i;
int root;

E.pool=0;
E.size=0;
E.mark=1;
E.free=-1;
E.cache_dirty=false;
for (i=0;i<CACHE_SIZE;i++) {
E.cache[i].parent=-1;
}
E.stack.data=0;
E.stack.top=0;

root=node_alloc(0);
assert(root==0);
stack_expand();
E.stack.data[E.stack.top++].stack=root;

E.stack.bottom=E.stack.top;
E.stack.current=E.stack.bottom-1;

E.map.table=0;
E.map.size=0;
E.map.free=0;
E.map.number=0;

map_expand();
}

/* release all the resource used in gc */

void
gc_exit()
{
int i;
清空pool

for (i=0;i<E.size;i++) {
my_free(E.pool[i].u.n.children);
if (E.pool[i].mark >= 0) {
void *p=E.pool[i].u.n.mem;
if (E.pool[i].u.n.finalizer && E.pool[i].u.c.weak!=WEAK_CONTAINER) {
E.pool[i].u.n.finalizer(p);
}
if ((intptr_t)p != FREED_POINTER) {
my_free(p);
}
}
}
my_free(E.pool);
清空hashmap

for (i=0;i<E.map.size;i++) {
struct hash_node *p=E.map.table[i];
while (p) {
struct hash_node *n=p->next;
my_free(p);
p=n;
}
}
my_free(E.map.table);
while (E.map.free) {
struct hash_node *p=E.map.free->next;
my_free(E.map.free);
E.map.free=p;
}
my_free(E.stack.data);
E.map.number=0;
}

/* mark the nodes related to root */
WeakContainer里的所有weakReferencemark值设置为当前E.mark

static __inline void
gc_mark_weak(int weak)
{
if (E.pool[weak].mark < E.mark) {
E.pool[weak].mark=E.mark;
}
}

static void
gc_mark(int root)
{
if (E.pool[root].mark < E.mark+1) {
struct link *children=E.pool[root].u.n.children;
E.pool[root].mark=E.mark+1;
if (children) {
int i;
if (E.pool[root].u.c.weak==WEAK_CONTAINER) {
bool merge=false;
for (i=children->number-1;i>=0;i--) {
int child=children->children[i];
if ((intptr_t)E.pool[child].u.n.mem == FREED_POINTER) {
children->children[i]=0;
merge=true;
}
else
gc_mark_weak(child);
}

if (merge) {     合并weakContainer里的free node
int j;
for (i=0;i<children->number;i++) {
if (children->children[i]==0) {     找到第一个为0的child
break;
}
}

for (j=i,++i;i<children->number;i++) {
if (children->children[i]!=0) {     取消所有为0的child
children->children[j++]=children->children[i];
}
}

children->number=j;
}
}
else {
for (i=children->number-1;i>=0;i--) {
gc_mark(children->children[i]);
}
}
}
}
}

/* collect the memory block can no longer be otherwise accessed */

void
gc_collect()
{
int i;
stack_pack();
cache_flush();
stack_pack与cache_flush的调用顺序不能改变。还是原引云风的说法“gc 最重要的一点,就是要对堆栈上的数据进行关联。在收集发生时,堆栈上所有临时分配出来的内存块都不应该被释放掉。”

gc_mark(0);
for (i=0;i<E.size;i++) {
if (E.pool[i].mark < E.mark) {
if (E.pool[i].mark >= 0) {     无视free node和才分配出来的node(这两者的mark均为-1)
void *p=E.pool[i].u.n.mem;
if (E.pool[i].u.n.finalizer && E.pool[i].u.c.weak!=WEAK_CONTAINER) {
E.pool[i].u.n.finalizer(p);
}
if ((intptr_t)p != FREED_POINTER) {
my_free(p);
map_erase(i);
}
node_free(i);
}
}
else if (E.pool[i].mark == E.mark) {     weakContainer里所有的weakReference每次都会被回收,但仍然保留了weakContainer与weanReference的关联关系,由gc_mark/gc_weak_next去负责清除。因此后面才仅仅设置了一个FREED_POINTER,而没有进行node_free

void *p=E.pool[i].u.n.mem;
if (E.pool[i].u.n.finalizer && E.pool[i].u.c.weak!=WEAK_CONTAINER) {
E.pool[i].u.n.finalizer(p);
E.pool[i].u.n.finalizer=0;
}

my_free(p);
map_erase(i);
E.pool[i].u.c.mem=FREED_POINTER;
}
}
E.mark+=2;
}

/* only for debug, print all the relationship of all nodes */

void
gc_dryrun()
{
int i;
printf("------dry run begin----\n");
stack_pack();
cache_flush();
gc_mark(0);
for (i=0;i<E.size;i++) {
struct link *link=E.pool[i].u.n.children;

if (E.pool[i].mark >= E.mark+1) {
if (E.pool[i].u.c.weak == WEAK_CONTAINER) {
printf("%d[weak] -> ",i);
}
else {
printf("%d(%p) -> ",i,E.pool[i].u.n.mem);
}
}
else if (E.pool[i].mark == E.mark) {
printf("w %d: ",i);
}
else if (E.pool[i].mark >= 0 ) {
printf("x %d(%p): ",i,E.pool[i].u.n.mem);
}
else {
continue;
}

if (link) {
int j;
for (j=0;j<link->number;j++) {
printf("%d,",link->children[j]);
}
}

printf("\n");
}
E.mark++;
printf("------dry run end------\n");
}

/* allocate a memory block , and create a node map to it. node will link to parent */

void*
gc_malloc(size_t sz,void *parent,void (*finalizer)(void *))
{
void *ret=my_malloc(sz);
int id=map_id(ret);
E.pool[id].u.n.finalizer=finalizer;
if (parent) {
gc_link(parent,0,ret);
}
else {
stack_push(id);
}
return ret;
}

struct gc_weak_table {
int node_id;
};

/* allocate a weak pointer container */

struct gc_weak_table*
gc_weak_table(void *parent)
{
struct gc_weak_table *ret=my_malloc(sizeof(*ret));
ret->node_id=map_id(ret);
E.pool[ret->node_id].u.c.weak=WEAK_CONTAINER;
if (parent) {
gc_link(parent,0,ret);
}
else {
stack_push(ret->node_id);
}
return ret;
}

/* iterate the weak container */

void*
gc_weak_next(struct gc_weak_table *cont,int *iter)
{
int i,j;
struct link *children;
cache_flush();
children = E.pool[cont->node_id].u.n.children;
if (children==0) {
return 0;
}

for (i = (iter==0 ? 0 : *iter) ;i < children->number; i++) {
int id=children->children[i];
if (id) {
if (E.pool[id].u.c.mem == FREED_POINTER) {
children->children[i] = 0;
}
else {
if (iter) {
*iter=i+1;
}
stack_push(id);
return E.pool[id].u.n.mem;
}
}
}

for (i=0;i<children->number;i++) {
if (children->children[i]==0) {
break;
}
}

for (j=i,++i;i<children->number;i++) {
if (children->children[i]!=0) {
children->children[j++]=children->children[i];
}
}

children->number=j;

return 0;
}

/* clone a memory block , this will copy all the edges linked to orginal node */

void*
gc_clone(void *from,size_t sz)
{
int from_id=map_id(from);
void *to=my_malloc(sz);
int to_id=map_id(to);
struct link *from_children=E.pool[from_id].u.n.children;
stack_push(to_id);

cache_flush();
memcpy(to,from,sz);
E.pool[to_id].u.n.finalizer=E.pool[from_id].u.n.finalizer;
E.pool[to_id].u.n.children=link_expand(E.pool[to_id].u.n.children,from_children->number);
memcpy(E.pool[to_id].u.n.children,from_children,sizeof(*from_children) + (from_children->number-1)*sizeof(int));
return to;
}

/* realloc a memory block , all the edages linked to it will be retained */

void*
gc_realloc(void *p,size_t sz,void *parent)
{
void *ret;
assert(sz>0);

if (p==0) {
return gc_malloc(sz,parent,0);
}

ret=my_realloc(p,sz);
if (ret==p) {
return ret;
}
else {     当重新分配内存后,原内存块被realloc移动到了新的合适的位置,这就导致了必须重新为其分配句柄,并且将原有link关系复制过去
int new_id=map_id(ret);
int old_id=map_id(p);

struct link *tmp=E.pool[new_id].u.n.children;
E.pool[new_id].u.n.children=E.pool[old_id].u.n.children;
E.pool[old_id].u.n.children=tmp;

E.pool[new_id].u.n.finalizer=E.pool[old_id].u.n.finalizer;

if (parent) {
gc_link(parent,p,ret);
}
else {
stack_push(new_id);
}
map_erase(old_id);
E.pool[old_id].u.c.mem=FREED_POINTER;
}

return ret;
}
分享到:
评论

相关推荐

    云风-lua源码欣赏-lua-5.21

    《云风-lua源码欣赏-lua-5.21》是一本专注于解析Lua 5.2.1版本源码的书籍。作者采用非线性写作方式,将各个章节独立完成,最后进行整体整合。书中的内容涵盖了Lua的多个核心方面,包括源文件划分、代码风格、虚拟机...

    云风《Lua源码欣赏》1积分

    《Lua源码欣赏》是一本由云风编写的书籍,旨在对Lua 5.2版本的源代码进行解析,为初学者提供了解Lua语言内部工作原理的途径。本书通过分解各个章节内容,使得读者能够以独立的形式学习和理解Lua的各个组成部分。 ...

    lua源码鉴赏云风

    《lua源码鉴赏云风》是一本专为对Lua编程语言有深厚兴趣并渴望深入理解其内部机制的读者所编写的书籍。作者云风,以其丰富的编程经验和深入的洞察力,揭示了Lua源码背后的设计哲学和技术实现,旨在帮助读者提升对Lua...

    lua程序编程-1与4版+云风lua源码赏析.zip

    programming in lua 4th,lua程序设计第4版,我学第一版的时候是200多页,现在2016年出的第四版还是200多页,更新了一些内容。还有国内大神云峰编写的《lua源码鉴赏》,分享出来一块学习进步吧。

    lua 源码鉴赏 readinglua 云风.zip

    《lua 源码鉴赏 readinglua 云风》是由知名游戏界人物云风创作的一份深入解析 Lua 脚本语言源码的文档。在本文档中,云风以其独特的视角和深入的理解,带领读者一同探索 Lua 的内部机制,揭示了这个小巧而强大的语言...

    lua源码导读---云风

    ### lua源码导读---云风 #### 概览 **Lua** 是一门轻量级、高效能的脚本语言,广泛应用于游戏开发、系统管理工具、网络应用等多个领域。本书《lua源码导读》旨在深入剖析 Lua 的源代码,帮助读者理解其内部实现...

    Lua源码欣赏2012年11月-云风.pdf

    在阅读这篇《Lua源码欣赏2012年11月-云风》文档之前,需要先明确文档所涉及的主题和内容。文档主要围绕着Lua语言的核心源码进行深入的分析和解读,涵盖了源代码文件划分、代码风格、核心实现、内置库实现、内存管理...

    我的编程感悟(附:云风写的风魂++2D引擎源码)

    我的编程感悟(附:云风写的风魂++2D引擎源码),很实在,很有用的文章

    云风WebShell管理器.rar

    【云风WebShell管理器】是一款专为网络安全专业人士设计的工具,主要用于管理和控制WebShell,即在网站服务器上植入的后门程序。WebShell通常是在非法入侵或安全测试时使用,以便远程操作服务器,执行各种命令,获取...

    风轻云淡挂 Q源码

    【风轻云淡挂Q源码】是一款针对QQ自动化管理的程序源代码,旨在帮助用户实现QQ账号的自动登录、消息处理以及一些日常维护功能。这个项目可能包含多个组件,如登录模块、消息处理模块、定时任务等,通过解析QQ的通信...

    云风pbc 库 示例

    - 理解C语言的编译和链接过程,如何将protobuf生成的源码与PBC库结合,形成一个完整的应用程序。 总的来说,这个示例提供了一个全面的学习路径,涵盖了protobuf和PBC库的使用,对于想要在C语言环境中处理序列化数据...

    云风《风魂2D游戏引擎》

    云风的风魂引擎源代码。VS2010+WIN7编译通过

    hive-master_with_my_common:云风的hive的源码阅读

    《云风的hive源码阅读指南》 Hive,作为大数据处理领域的重要工具,以其SQL-like接口和灵活性深受广大开发者喜爱。"hive-master_with_my_common"项目,是针对Hive源码的一次深入探索,由知名技术专家云风提供,旨在...

    云风的Ejoy2D-Engine

    从"ejoy2d-master"这个文件名来看,这很可能是Ejoy2D的源码仓库,包含了完整的Ejoy2D引擎源代码。通过研究这个仓库,开发者可以深入了解Ejoy2D的实现细节,对于想要定制或扩展引擎功能的开发者来说,这是一个宝贵的...

    云风写的垃圾回收库

    在云风的项目中,"manualgc"可能是源代码或者示例程序的名字,它代表了手动控制垃圾回收的接口或实例。学习这个库,开发者可以学习到如何在自己的C语言项目中集成垃圾回收功能,以及如何设计和实现一个简单的垃圾...

    云风的 BLOG- 采访 Lua 发明人的一篇文章

    《云风的 BLOG- 采访 Lua 发明人的一篇文章》是关于编程语言 Lua 的深度探讨,这篇博客文章详尽地记录了云风对 Lua 的发明者之一的访谈过程,揭示了 Lua 的设计理念和背后的故事。Lua 是一种轻量级、高效、可扩展的...

    《那些日子》- 云风

    "云风:那些日子" 云风是中国开源游戏引擎开发的第一人,也是梦幻西游的作者,windsoul(风魂)的作者。通过这篇文章,我们可以了解云风的编程感悟和他在游戏开发过程中的经验。 云风认为,记忆是非常重要的,他...

    游戏之旅-我的编程感悟云风

    游戏之旅-我的编程感悟,云风大神的编程感悟,不知道云风是谁吗???

    云风伙伴算法代码

    这个内存分配器需要是非入侵式的,即不在要分配的内存块中写 cookie 。 而我的需求中,需要被管理的内存块都是很规则的,成 2 的整数次幂的长度。buddy memory allocation 刚好适用。 算法很简单,就是每次把一个...

    云风最新的2D引擎

    《云风2D引擎:深度探索与应用》 在当今的数字媒体领域,2D游戏引擎扮演着至关重要的角色,而“云风最新的2D引擎”正是这样一款备受瞩目的技术成果。它以其高效、易用和强大的特性,为开发者提供了全新的创作平台。...

Global site tag (gtag.js) - Google Analytics