Commit a656f820 authored by Jan Ziak's avatar Jan Ziak Committed by Russ Cox

runtime: precise garbage collection of channels

This changeset adds a mostly-precise garbage collection of channels.
The garbage collection support code in the linker isn't recognizing
channel types yet.

Fixes issue http://stackoverflow.com/questions/14712586/memory-consumption-skyrocket

R=dvyukov, rsc, bradfitz
CC=dave, golang-dev, minux.ma, remyoudompheng
https://golang.org/cl/7307086
parent 707ab134
...@@ -33,6 +33,8 @@ struct WaitQ ...@@ -33,6 +33,8 @@ struct WaitQ
SudoG* last; SudoG* last;
}; };
// The garbage collector is assuming that Hchan can only contain pointers into the stack
// and cannot contain pointers into the heap.
struct Hchan struct Hchan
{ {
uintgo qcount; // total data in the q uintgo qcount; // total data in the q
...@@ -48,6 +50,8 @@ struct Hchan ...@@ -48,6 +50,8 @@ struct Hchan
Lock; Lock;
}; };
uint32 runtime·Hchansize = sizeof(Hchan);
// Buffer follows Hchan immediately in memory. // Buffer follows Hchan immediately in memory.
// chanbuf(c, i) is pointer to the i'th slot in the buffer. // chanbuf(c, i) is pointer to the i'th slot in the buffer.
#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i)) #define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
...@@ -112,6 +116,7 @@ runtime·makechan_c(ChanType *t, int64 hint) ...@@ -112,6 +116,7 @@ runtime·makechan_c(ChanType *t, int64 hint)
c->elemalg = elem->alg; c->elemalg = elem->alg;
c->elemalign = elem->align; c->elemalign = elem->align;
c->dataqsiz = hint; c->dataqsiz = hint;
runtime·settype(c, (uintptr)t | TypeInfo_Chan);
if(debug) if(debug)
runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elemalign=%d; dataqsiz=%D\n", runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elemalign=%d; dataqsiz=%D\n",
......
...@@ -482,6 +482,7 @@ enum ...@@ -482,6 +482,7 @@ enum
TypeInfo_SingleObject = 0, TypeInfo_SingleObject = 0,
TypeInfo_Array = 1, TypeInfo_Array = 1,
TypeInfo_Map = 2, TypeInfo_Map = 2,
TypeInfo_Chan = 3,
// Enables type information at the end of blocks allocated from heap // Enables type information at the end of blocks allocated from heap
DebugTypeAtBlockEnd = 0, DebugTypeAtBlockEnd = 0,
......
...@@ -164,6 +164,7 @@ static struct { ...@@ -164,6 +164,7 @@ static struct {
enum { enum {
GC_DEFAULT_PTR = GC_NUM_INSTR, GC_DEFAULT_PTR = GC_NUM_INSTR,
GC_MAP_NEXT, GC_MAP_NEXT,
GC_CHAN,
}; };
// markonly marks an object. It returns true if the object // markonly marks an object. It returns true if the object
...@@ -521,6 +522,9 @@ static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR}; ...@@ -521,6 +522,9 @@ static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR};
// Hashmap iterator program // Hashmap iterator program
static uintptr mapProg[2] = {0, GC_MAP_NEXT}; static uintptr mapProg[2] = {0, GC_MAP_NEXT};
// Hchan program
static uintptr chanProg[2] = {0, GC_CHAN};
// Local variables of a program fragment or loop // Local variables of a program fragment or loop
typedef struct Frame Frame; typedef struct Frame Frame;
struct Frame { struct Frame {
...@@ -560,6 +564,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) ...@@ -560,6 +564,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
bool didmark, mapkey_kind, mapval_kind; bool didmark, mapkey_kind, mapval_kind;
struct hash_gciter map_iter; struct hash_gciter map_iter;
struct hash_gciter_data d; struct hash_gciter_data d;
Hchan *chan;
ChanType *chantype;
if(sizeof(Workbuf) % PageSize != 0) if(sizeof(Workbuf) % PageSize != 0)
runtime·throw("scanblock: size of Workbuf is suboptimal"); runtime·throw("scanblock: size of Workbuf is suboptimal");
...@@ -601,6 +607,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) ...@@ -601,6 +607,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
mapkey_size = mapval_size = 0; mapkey_size = mapval_size = 0;
mapkey_kind = mapval_kind = false; mapkey_kind = mapval_kind = false;
mapkey_ti = mapval_ti = 0; mapkey_ti = mapval_ti = 0;
chan = nil;
chantype = nil;
goto next_block; goto next_block;
...@@ -660,6 +668,11 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) ...@@ -660,6 +668,11 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
goto next_block; goto next_block;
} }
break; break;
case TypeInfo_Chan:
chan = (Hchan*)b;
chantype = (ChanType*)t;
pc = chanProg;
break;
default: default:
runtime·throw("scanblock: invalid type"); runtime·throw("scanblock: invalid type");
return; return;
...@@ -897,6 +910,26 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) ...@@ -897,6 +910,26 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
pc += 4; pc += 4;
break; break;
case GC_CHAN:
// There are no heap pointers in struct Hchan,
// so we can ignore the leading sizeof(Hchan) bytes.
if(!(chantype->elem->kind & KindNoPointers)) {
// Channel's buffer follows Hchan immediately in memory.
// Size of buffer (cap(c)) is second int in the chan struct.
n = ((uintgo*)chan)[1];
if(n > 0) {
// TODO(atom): split into two chunks so that only the
// in-use part of the circular buffer is scanned.
// (Channel routines zero the unused part, so the current
// code does not lead to leaks, it's just a little inefficient.)
*objbufpos++ = (Obj){(byte*)chan+runtime·Hchansize, n*chantype->elem->size,
(uintptr)chantype->elem->gc | PRECISE | LOOP};
if(objbufpos == objbuf_end)
flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
}
}
goto next_block;
default: default:
runtime·throw("scanblock: invalid GC instruction"); runtime·throw("scanblock: invalid GC instruction");
return; return;
......
...@@ -609,6 +609,7 @@ extern int32 runtime·ncpu; ...@@ -609,6 +609,7 @@ extern int32 runtime·ncpu;
extern bool runtime·iscgo; extern bool runtime·iscgo;
extern void (*runtime·sysargs)(int32, uint8**); extern void (*runtime·sysargs)(int32, uint8**);
extern uint32 runtime·maxstring; extern uint32 runtime·maxstring;
extern uint32 runtime·Hchansize;
/* /*
* common functions and data * common functions and data
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment