Tôi đã luôn luôn nhầm lẫn về ký ức dân cư ngày càng tăng của các ứng dụng Go tôi, và cuối cùng tôi đã phải học những công cụ profiling có mặt trong hệ sinh thái Go. Thời gian chạy cung cấp nhiều số liệu trong cấu trúc runtime.Memstats, nhưng có thể khó hiểu được cấu trúc nào trong số chúng có thể giúp tìm ra lý do phát triển bộ nhớ, do đó cần một số công cụ bổ sung.
Profiling môi trường
Sử dụng https://github.com/tevjef/go-runtime-metrics trong ứng dụng của bạn. Ví dụ, bạn có thể đặt điều này trong main
của bạn:
import(
metrics "github.com/tevjef/go-runtime-metrics"
)
func main() {
//...
metrics.DefaultConfig.CollectionInterval = time.Second
if err := metrics.RunCollector(metrics.DefaultConfig); err != nil {
// handle error
}
}
Run InfluxDB
và Grafana
trong Docker
container:
docker run --name influxdb -d -p 8086:8086 influxdb
docker run -d -p 9090:3000/tcp --link influxdb --name=grafana grafana/grafana:4.1.0
Thiết lập tương tác giữa Grafana
và InfluxDB
Grafana
(trang chính Grafana -> góc trên cùng bên trái -> Dữ liệu -> Thêm nguồn dữ liệu mới):
nhập bảng điều khiển #3242 từ https://grafana.com (trang chính Grafana -> trái góc trên -> Dashboard -> Import):
Cuối cùng, khởi động ứng dụng của bạn: nó sẽ truyền số liệu thời gian chạy đến contenerized Influxdb
.Đặt ứng dụng của bạn dưới một tải hợp lý (trong trường hợp của tôi nó là khá nhỏ - 5 RPS trong một vài giờ).
tiêu thụ bộ nhớ phân tích
Sys
(các synonim của RSS
) đường cong khá giống với HeapSys
đường cong. Hóa ra phân bổ bộ nhớ động là yếu tố chính của sự tăng trưởng bộ nhớ tổng thể, do đó, lượng bộ nhớ nhỏ được tiêu thụ bởi các biến stack dường như không đổi và có thể bỏ qua;
- Số tiền không đổi của goroutines garantees sự vắng mặt của rò rỉ goroutine/stack biến rò rỉ;
- Tổng số lượng đối tượng được phân bổ vẫn giữ nguyên (không có điểm trong việc tính đến các biến động) trong suốt thời gian tồn tại của quá trình.
- Thực tế đáng ngạc nhiên nhất:
HeapIdle
đang tăng với tỷ lệ giống như Sys
, trong khi HeapReleased
luôn bằng 0. Rõ ràng thời gian chạy không trả lại bộ nhớ để OS ở tất cả, ít nhất là theo các điều kiện của thử nghiệm này:
HeapIdle minus HeapReleased estimates the amount of memory
that could be returned to the OS, but is being retained by
the runtime so it can grow the heap without requesting more
memory from the OS.
Đối với những người đang cố gắng để điều tra vấn đề tiêu thụ bộ nhớ Tôi khuyên bạn nên làm theo các bước được mô tả để loại trừ một số lỗi nhỏ (như rò rỉ goroutine).
Giải phóng bộ nhớ một cách rõ ràng
Thật thú vị khi một trong những có thể làm giảm đáng kể mức tiêu thụ bộ nhớ với các cuộc gọi rõ ràng để debug.FreeOSMemory()
:
// in the top-level package
func init() {
go func() {
t := time.Tick(time.Second)
for {
<-t
debug.FreeOSMemory()
}
}()
}
Trong thực tế, phương pháp này tiết kiệm khoảng 35% bộ nhớ so với các điều kiện mặc định.
Xem thêm
https://github.com/golang/go/issues/14521
bài viết mã của bạn. Cho chúng tôi biết chương trình của bạn làm gì. – elithrar
Có thể vì một gc? http://dave.cheney.net/2014/07/11/visualising-the-go-garbage-collector có thể giúp ích. – VonC
Dường như bộ nhớ remaning không được thu thập được thu thập và phát hành cho hệ thống. Nó được thực hiện sau một vài phút không hoạt động. Đợi 8 phút và kiểm tra lại. Kiểm tra liên kết này để biết hướng dẫn về cách gỡ lỗi/hồ sơ Đi chương trình: https://software.intel.com/en-us/blogs/2014/05/10/debugging-performance-issues-in-go-programs – siritinga