Tôi đang gặp vấn đề khi Bắt đầu chơi độc đáo với SQLite, tôi đã làm điều đó trong quá khứ mà không gặp sự cố nhưng đã mất một thời gian và tôi không nhớ mình đã làm gì làm việc đúng cách. Tôi đang sử dụng Go cùng với gói mattn/go-sqlite3
để xử lý và chèn rất nhiều dữ liệu vào cơ sở dữ liệu SQLite nhưng bằng cách nào đó, Go luôn kết thúc việc ăn tất cả RAM của tôi cho đến khi cuối cùng thoát với mã trạng thái lỗi. Chỉ cần chắc chắn rằng tôi đã cô lập các vấn đề bộ nhớ đói để SQLite tôi đã viết các chương trình đơn giản sau đây để kiểm tra nó ra:SQLite 3 không giải phóng bộ nhớ trong Golang
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./test.db"); if err != nil {
log.Fatal(err)
}; defer db.Close()
ddl := `
PRAGMA automatic_index = ON;
PRAGMA cache_size = 32768;
PRAGMA cache_spill = OFF;
PRAGMA foreign_keys = ON;
PRAGMA journal_size_limit = 67110000;
PRAGMA locking_mode = NORMAL;
PRAGMA page_size = 4096;
PRAGMA recursive_triggers = ON;
PRAGMA secure_delete = ON;
PRAGMA synchronous = NORMAL;
PRAGMA temp_store = MEMORY;
PRAGMA journal_mode = WAL;
PRAGMA wal_autocheckpoint = 16384;
CREATE TABLE IF NOT EXISTS "user" (
"id" TEXT,
"username" TEXT,
"password" TEXT
);
CREATE UNIQUE INDEX IF NOT EXISTS "id" ON "user" ("id");
`
_, err = db.Exec(ddl); if err != nil {
log.Fatal(err)
}
queries := map[string]*sql.Stmt{}
queries["user"], _ = db.Prepare(`INSERT OR REPLACE INTO "user" VALUES (?, ?, ?);`); if err != nil {
log.Fatal(err)
}; defer queries["user"].Close()
tx, err := db.Begin(); if err != nil {
log.Fatal(err)
}
for i := 0; i < 10000000; i++ {
user := map[string]string{
"id": string(i),
"username": "foo",
"password": "bar",
}
_, err := tx.Stmt(queries["user"]).Exec(user["id"], user["username"], user["password"]); if err != nil {
log.Fatal(err)
}
if i % 32768 == 0 {
tx.Commit()
db.Exec(`PRAGMA shrink_memory;`)
tx, err = db.Begin(); if err != nil {
log.Fatal(err)
}
fmt.Println(i)
}
}
tx.Commit()
}
Khi tôi chạy đoạn mã trên, Gò ăn hơn 100 MiB bộ nhớ mỗi giây mà không cần mỗi phát hành bất kỳ, sau một phút hoặc lâu hơn nó kết thúc tiêu thụ 6/7 GiB và sau đó quá trình bị giết. Tôi đã thử các biến thể có và không xác định các PRAGMA SQLite nhưng không có may mắn.
Theo các PRAGMA được xác định, SQLite không bao giờ nên sử dụng nhiều hơn 128 MiB RAM.
Tôi đã thực hiện bất kỳ sai lầm nào hoặc có vấn đề gì với mattn/go-sqlite3 hoặc Go GC không?
Profiling với davecheney/profile
theo these instructions mang lại sản lượng không quá hữu ích này:
[email protected]:~/Go/src$ go tool pprof --text ./test /tmp/profile102098478/mem.pprof
Adjusting heap profiles for 1-in-4096 sampling rate
Total: 0.0 MB
0.0 100.0% 100.0% 0.0 100.0% runtime.allocm
0.0 0.0% 100.0% 0.0 100.0% database/sql.(*DB).Exec
0.0 0.0% 100.0% 0.0 100.0% database/sql.(*DB).conn
0.0 0.0% 100.0% 0.0 100.0% database/sql.(*DB).exec
0.0 0.0% 100.0% 0.0 100.0% github.com/mattn/go-sqlite3.(*SQLiteDriver).Open
0.0 0.0% 100.0% 0.0 100.0% github.com/mattn/go-sqlite3._Cfunc_sqlite3_threadsafe
0.0 0.0% 100.0% 0.0 100.0% main.main
0.0 0.0% 100.0% 0.0 100.0% runtime.cgocall
0.0 0.0% 100.0% 0.0 100.0% runtime.gosched0
0.0 0.0% 100.0% 0.0 100.0% runtime.main
0.0 0.0% 100.0% 0.0 100.0% runtime.newextram
Đây là chỉ dành riêng cho 1000000 lặp và bộ nhớ vẫn mọc như không có tomorow.
Tôi cũng thử mã tương tự trên hai MacBook Pros, cả hai đều chạy phiên bản mới nhất của Go từ brew (1.3.1), một trong số đó sử dụng bộ nhớ đứng đầu 10 GiB và trung bình 2 GiB tiêu thụ RAM khác. Điều này trông giống như một hành vi kỳ quặc, tôi có thể làm gì để theo dõi sự khác biệt và sửa lỗi hogging bộ nhớ?
Chạy đi phiên bản go1.2.1 linux/amd64. –
Bạn có thể hài hước và xóa bản đồ 'người dùng' không? Chỉ cần vượt qua các giá trị và xem có bao nhiêu thay đổi sử dụng bộ nhớ của bạn? –
@SimonWhitehead: Chỉ cần làm, không thể nói đó là bất kỳ khác nhau - về việc sử dụng bộ nhớ lặp đi lặp lại 1081344 đã đạt 5 GiB rồi. –