Skip to content

Commit f763d6d

Browse files
committed
optimize gc and add tests for GC
1 parent 9f99064 commit f763d6d

File tree

2 files changed

+104
-15
lines changed

2 files changed

+104
-15
lines changed

aio_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,3 +971,76 @@ func BenchmarkContextSwitch(b *testing.B) {
971971
}
972972
close(die)
973973
}
974+
975+
func TestGC(t *testing.T) {
976+
par := 1024
977+
msgsize := 65536
978+
t.Log("testing GC:", par, "connections")
979+
ln := echoServer(t, msgsize)
980+
defer ln.Close()
981+
982+
w, err := NewWatcher()
983+
if err != nil {
984+
t.Fatal(err)
985+
}
986+
defer w.Close()
987+
988+
for i := 0; i < par; i++ {
989+
go func() {
990+
data := make([]byte, msgsize)
991+
conn, err := net.Dial("tcp", ln.Addr().String())
992+
if err != nil {
993+
log.Fatal(err)
994+
}
995+
996+
// send
997+
err = w.Write(nil, conn, data)
998+
if err != nil {
999+
log.Fatal(err)
1000+
}
1001+
1002+
conn = nil
1003+
}()
1004+
}
1005+
1006+
count := 0
1007+
LOOP:
1008+
for {
1009+
results, err := w.WaitIO()
1010+
if err != nil {
1011+
t.Fatal("waitio:", err)
1012+
return
1013+
}
1014+
1015+
for _, res := range results {
1016+
switch res.Operation {
1017+
case OpWrite:
1018+
case OpRead:
1019+
}
1020+
res.Conn = nil
1021+
1022+
count++
1023+
if count >= par {
1024+
break LOOP
1025+
}
1026+
}
1027+
}
1028+
1029+
found, closed := w.GetGC()
1030+
t.Logf("GC found:%d closed:%d", found, closed)
1031+
<-time.After(2 * time.Second)
1032+
runtime.GC()
1033+
1034+
found, closed = w.GetGC()
1035+
t.Logf("GC found:%d closed:%d", found, closed)
1036+
<-time.After(2 * time.Second)
1037+
runtime.GC()
1038+
1039+
found, closed = w.GetGC()
1040+
t.Logf("GC found:%d closed:%d", found, closed)
1041+
<-time.After(2 * time.Second)
1042+
runtime.GC()
1043+
1044+
found, closed = w.GetGC()
1045+
t.Logf("GC found:%d closed:%d", found, closed)
1046+
}

watcher.go

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,11 @@ type watcher struct {
9696
timer *time.Timer // Timer for handling timeouts
9797

9898
// Garbage collection
99-
gc []net.Conn // List of connections to be garbage collected
99+
gc []uintptr // List of connections to be garbage collected
100100
gcMutex sync.Mutex // Mutex to synchronize access to the gc list
101101
gcNotify chan struct{} // Channel to notify the GC processor
102+
gcFound uint32 // number of net.Conn objects found unreachable by runtime
103+
gcClosed uint32 // record number of objects closed successfully
102104

103105
// Shutdown and cleanup
104106
die chan struct{} // Channel for signaling shutdown
@@ -571,19 +573,8 @@ func (w *watcher) loop() {
571573
break
572574
}
573575
}
574-
575-
case <-w.gcNotify: // GC recycled net.Conn
576-
w.gcMutex.Lock()
577-
for i, c := range w.gc {
578-
ptr := reflect.ValueOf(c).Pointer()
579-
if ident, ok := w.connIdents[ptr]; ok {
580-
w.releaseConn(ident)
581-
}
582-
w.gc[i] = nil
583-
}
584-
w.gc = w.gc[:0]
585-
w.gcMutex.Unlock()
586-
576+
case <-w.gcNotify:
577+
w.handleGC()
587578
case cpuid := <-w.chCPUID:
588579
setAffinity(cpuid)
589580

@@ -593,6 +584,22 @@ func (w *watcher) loop() {
593584
}
594585
}
595586

587+
// handleGC processes the garbage collection of net.Conn objects.
588+
func (w *watcher) handleGC() {
589+
runtime.GC()
590+
w.gcMutex.Lock()
591+
if len(w.gc) > 0 {
592+
for _, ptr := range w.gc {
593+
if ident, ok := w.connIdents[ptr]; ok {
594+
w.releaseConn(ident)
595+
}
596+
}
597+
w.gcClosed += uint32(len(w.gc))
598+
w.gc = w.gc[:0]
599+
}
600+
w.gcMutex.Unlock()
601+
}
602+
596603
// handlePending processes new requests, acting as a reception desk.
597604
func (w *watcher) handlePending(pending []*aiocb) {
598605
PENDING:
@@ -641,7 +648,9 @@ PENDING:
641648
// if not it will never be GC-ed.
642649
runtime.SetFinalizer(pcb.conn, func(c net.Conn) {
643650
w.gcMutex.Lock()
644-
w.gc = append(w.gc, c)
651+
ptr := reflect.ValueOf(c).Pointer()
652+
w.gc = append(w.gc, ptr)
653+
w.gcFound++
645654
w.gcMutex.Unlock()
646655

647656
// notify gc processor
@@ -741,3 +750,10 @@ func (w *watcher) handleEvents(events pollerEvents) {
741750
}
742751
}
743752
}
753+
754+
// read gcFound & gcClosed
755+
func (w *watcher) GetGC() (found uint32, closed uint32) {
756+
w.gcMutex.Lock()
757+
defer w.gcMutex.Unlock()
758+
return w.gcFound, w.gcClosed
759+
}

0 commit comments

Comments
 (0)