go项目

1、循环使用缓存

每条日志需要开辟缓存块来存储内容,以减少频繁的内存分配与回收。日志结构体定义如下:

type MLogger struct {

	// freeList is a list of byte buffers, maintained under freeListMu.
	freeList *buffer
	// freeListMu maintains the free list. It is separate from the main mutex
	// so buffers can be grabbed and printed to without holding the main lock,
	// for better parallelization.
	freeListMu sync.Mutex

        // ...
}

已经开辟出的多个内存空间形成一个单链表,其中的freeList指向这个链表的头部。由于有多个go协程同时要操作这个单链表,如打印完日志后回收缓存,或者要求一个缓存块来存储日志内容。

首先看一下缓存的回收方法,如下::

// putBuffer returns a buffer to the free list.
func (l *MLogger) putBuffer(b *buffer) {
	if b.Len() >= 1500 {
		fmt.Println("buffer:%d\n",b.Len())
		return // Let big buffers die a natural death(自然死).
	}
	l.freeListMu.Lock() // 上锁

	b.next = l.freeList // 为下一个可用的buffer设置值
	l.freeList = b      // 为当前可用的freeList设置buffer

	l.freeListMu.Unlock() // 解锁
}

当开辟的缓存块过大时不进行重复利用,以释放这些内存空间。

最主要的操作就是将不需要的缓存块插入到单链表的头部,然后让freeList指针指向新插入的缓存块即可。

获取缓存块: 

// getBuffer returns a new, ready-to-use buffer. (获取一个新的,可使用的缓存)
func (l *MLogger) getBuffer() *buffer {
	l.freeListMu.Lock() // 上锁

	b := l.freeList
	if b != nil {
		l.freeList = b.next
	}
	l.freeListMu.Unlock() // 解锁

	if b == nil {
		b = new(buffer)
	} else {
		b.next = nil
		b.Reset()
	}

	return b
}

在获取缓存块时需要优先考虑freeList中可用的缓存块,如果有就从链表头部取一个块返回(注意:必须调用Reset()方法,因为这个块中还缓存有上一次日志的信息),否则就创建一个新的缓存块返回。

  

  

猜你喜欢

转载自www.cnblogs.com/mazhimazhi/p/9071840.html