dnsproxy
dnsproxy copied to clipboard
关于内存泄露问题
感谢作者的奉献,我在使用过程中发现一些内存的问题,实测如下
线程过多
github.com/miekg/dns/server.go
for srv.isStarted() {
m, s, err := reader.ReadUDP(l, rtimeout)
if err != nil {
if !srv.isStarted() {
return nil
}
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
continue
}
return err
}
if len(m) < headerSize {
if cap(m) == srv.UDPSize {
srv.udpPool.Put(m[:srv.UDPSize])
}
continue
}
wg.Add(1)
go srv.serveUDPPacket(&wg, m, l, s)
}
我在windows使用此代理,然后用200个线程去nslookup,发现线程数不断增加,貌似在"github.com/miekg/dns"库中,并没有对UDP线程数进行限制,所以需要自己写一个UDP线程数限制的server,而不能直接拿过来用。
内存泄露
libdns_utils.go
func (dt *DnsTransPort) legallySpawnExchange(req *dns.Msg) (*dns.Msg, error) {
const spawnNum int8 = 3
resp := make(chan *dns.Msg, spawnNum)
lastErr := make(chan error)
var failedTimes int32
for range [spawnNum]struct{}{} {
go func() {
if r, err := dt.Exchange(req); err == nil {
resp <- r
} else {
if atomic.LoadInt32(&failedTimes) == int32(spawnNum-1) {
resp <- nil
lastErr <- err
} else {
atomic.AddInt32(&failedTimes, 1)
}
}
}()
}
if r := <-resp; r != nil {
return r, nil
} else {
return nil, <-lastErr
}
}
在libdns_utils.go文件的legallySpawnExchange文件中,起了3个线程发给同一个server,在线程比较多的情况下(我用的200个),其中1个线程返回,另外2个线程可能因为争抢资源而一直存在,导致goroutine一直增加,建议还是不要增加线程,直接在主线程中跑
以上200线程有点夸张,但我实际部署中确实存在个别机器暴内存的现象,原因可以是电脑负载较重或本身资源有限,使用200线程可以在任意电脑复现