Comments (17)
This is memory usage of small program below for 7 minutes.
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
)
func main() {
f := func() {
db, err := sql.Open("sqlite3", "file::memory:")
if err != nil {
panic(err)
}
defer db.Close()
if _, err := db.Exec(`CREATE TABLE dummy_table (id INT PRIMARY KEY,f1 VARCHAR(50),f2 VARCHAR(50),f3 VARCHAR(50),f4 VARCHAR(50),f5 VARCHAR(50),f6 VARCHAR(50),f7 VARCHAR(50),f8 VARCHAR(50),f9 VARCHAR(50),f10 VARCHAR(50));`); err != nil {
panic(err)
}
insert := "INSERT INTO dummy_table (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES "
for i := 0; i < 9999; i += 1 {
insert += fmt.Sprintf(`("%s","%s","%s","%s","%s","%s","%s","%s","%s","%s")`, "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111")
insert += ","
}
insert = insert[:len(insert)-1]
if _, err := db.Exec(insert); err != nil {
panic(err)
}
}
for {
f()
}
}
from go-sqlite3.
from go-sqlite3.
Thanks for response. Forgot to mention, I've tested on a web server, for requests with same table data, memory do not increase after a while, but it's not going down anyway. for requests with different table datas, memory keep growing and go OOM killed finally.
from go-sqlite3.
Looks like for this simple program, it's mem usage stops at some point after a while. But I think the key problem in this case is that, the big part of memory cost is never getting gc. It's more obvious in a webserver. In a real production server of mime which accepts various table structure and data, it's getting OOM killed very fast.
If I remove the db insert usage, just create the big insert string and let go, the mem usage drops soon and keep at a low level about 10mb.
from go-sqlite3.
@wxsms could it be that defer db.Close() never runs? Try move it before the r.GET() as the main function is never returning.
func main() {
r := gin.Default()
kdb, err := sql.Open("sqlite3", "file::memory:")
if err != nil {
panic(err)
}
defer db.Close()
r.GET("/run", func(c *gin.Context) {
if _, err := db.Exec(`CREATE TABLE dummy_table (id INT PRIMARY KEY,f1 VARCHAR(50),f2 VARCHAR(50),f3 VARCHAR(50),f4 VARCHAR(50),f5 VARCHAR(50),f6 VARCHAR(50),f7 VARCHAR(50),f8 VARCHAR(50),f9 VARCHAR(50),f10 VARCHAR(50));`); err != nil {
panic(err)
}
insert := "INSERT INTO dummy_table (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES "
for i := 0; i < 9999; i += 1 {
insert += fmt.Sprintf(`("%s","%s","%s","%s","%s","%s","%s","%s","%s","%s")`, "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111")
insert += ","
}
insert = insert[:len(insert)-1]
if _, err := db.Exec(insert); err != nil {
panic(err)
}
c.String(200, "OK")
})
r.Run(":8080")
}
from go-sqlite3.
I figured out this behavior. This is not related on go-sqlite3.
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
)
var _ = fmt.Sprint
var insert string
func init() {
insert = "INSERT INTO dummy_table (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES "
for i := 0; i < 9999; i += 1 {
insert += fmt.Sprintf(`("%s","%s","%s","%s","%s","%s","%s","%s","%s","%s")`, "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111")
insert += ","
}
insert = insert[:len(insert)-1]
}
func f() error {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
return err
}
defer db.Close()
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
db.SetConnMaxIdleTime(0)
db.SetConnMaxLifetime(0)
if _, err := db.Exec(`CREATE TABLE dummy_table (id INT PRIMARY KEY,f1 VARCHAR(50),f2 VARCHAR(50),f3 VARCHAR(50),f4 VARCHAR(50),f5 VARCHAR(50),f6 VARCHAR(50),f7 VARCHAR(50),f8 VARCHAR(50),f9 VARCHAR(50),f10 VARCHAR(50));`); err != nil {
return err
}
if _, err := db.Exec(insert); err != nil {
return err
}
insert = ""
return nil
}
func main() {
for {
fmt.Println(f())
}
}
This code does not increse memory.
The reason of incresing memory in your code (and first my PoC) is simply an appending many values into variable insert
.
from go-sqlite3.
the insert = ""
in your code makes it run nothing on 2+ rounds. maybe this is why memory doesnt increase in such case.
from go-sqlite3.
I just updated my reproduce: https://github.com/wxsms/go-sqlite3-memleak , which create a insert string at the init function and reuse on every run. The memleak is still there. @mattn
from go-sqlite3.
Please try test without gin gonic.
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
"runtime"
)
var insert string
func init() {
insert = "INSERT INTO dummy_table (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES "
for i := 0; i < 9999; i += 1 {
insert += fmt.Sprintf(`("%s","%s","%s","%s","%s","%s","%s","%s","%s","%s")`, "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111")
insert += ","
}
insert = insert[:len(insert)-1]
}
func f() {
db, err := sql.Open("sqlite3", "file::memory:")
if err != nil {
panic(err)
}
defer db.Close()
if _, err := db.Exec(`CREATE TABLE dummy_table (id INT PRIMARY KEY,f1 VARCHAR(50),f2 VARCHAR(50),f3 VARCHAR(50),f4 VARCHAR(50),f5 VARCHAR(50),f6 VARCHAR(50),f7 VARCHAR(50),f8 VARCHAR(50),f9 VARCHAR(50),f10 VARCHAR(50));`); err != nil {
panic(err)
}
if _, err := db.Exec(insert); err != nil {
panic(err)
}
}
func main() {
for {
f()
runtime.GC()
}
}
from go-sqlite3.
from go-sqlite3.
It is possible to be a memory leak of github.com/gin-gonic/gin.
from go-sqlite3.
from go-sqlite3.
ok. I remove the gin framework. but as I mention before, the key problem is:
for requests with same table data, memory do not increase after a while, but it's not going down anyway
please see this code
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
"runtime"
"time"
)
var insert string
func init() {
insert = "INSERT INTO dummy_table (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES "
for i := 0; i < 9999; i += 1 {
insert += fmt.Sprintf(`("%s","%s","%s","%s","%s","%s","%s","%s","%s","%s")`, "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111")
insert += ","
}
insert = insert[:len(insert)-1]
}
func f() {
db, err := sql.Open("sqlite3", "file::memory:")
if err != nil {
panic(err)
}
defer db.Close()
if _, err := db.Exec(`CREATE TABLE dummy_table (id INT PRIMARY KEY,f1 VARCHAR(50),f2 VARCHAR(50),f3 VARCHAR(50),f4 VARCHAR(50),f5 VARCHAR(50),f6 VARCHAR(50),f7 VARCHAR(50),f8 VARCHAR(50),f9 VARCHAR(50),f10 VARCHAR(50));`); err != nil {
panic(err)
}
if _, err := db.Exec(insert); err != nil {
panic(err)
}
}
func main() {
idx := 0
for {
fmt.Printf("round %d\n", idx)
f()
runtime.GC()
idx++
if idx == 5 {
// we sleep here to wait for gc
time.Sleep(time.Hour * 111)
}
}
}
After 5 rounds of running, the memory is about 110mb, and never drops. Which behave the same as using gin webserver.
If we add sleep for each round after runtime.GC()
, we can also see that the memory on startup is about 15mb, and every round running it increase ~20mb.
from go-sqlite3.
Calling runtime.GC does not necessarily trigger GC every time. GC will not be triggered until a certain threshold is reached.
from go-sqlite3.
This is a result of 5 minutes.
from go-sqlite3.
Please try this.
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
"runtime"
)
var insert string
func init() {
insert = "INSERT INTO dummy_table (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) VALUES "
for i := 0; i < 9999; i += 1 {
insert += fmt.Sprintf(`("%s","%s","%s","%s","%s","%s","%s","%s","%s","%s")`, "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111", "1111111111")
insert += ","
}
insert = insert[:len(insert)-1]
}
func f() {
db, err := sql.Open("sqlite3", "file::memory:")
if err != nil {
panic(err)
}
defer db.Close()
if _, err := db.Exec(`CREATE TABLE dummy_table (id INT PRIMARY KEY,f1 VARCHAR(50),f2 VARCHAR(50),f3 VARCHAR(50),f4 VARCHAR(50),f5 VARCHAR(50),f6 VARCHAR(50),f7 VARCHAR(50),f8 VARCHAR(50),f9 VARCHAR(50),f10 VARCHAR(50));`); err != nil {
panic(err)
}
if _, err := db.Exec(insert); err != nil {
panic(err)
}
}
func main() {
var m runtime.MemStats
for {
f()
runtime.GC()
runtime.ReadMemStats(&m)
fmt.Printf("Alloc = %v\n", m.Alloc)
}
}
You should understand that Go using memory for runtime too.
from go-sqlite3.
Thank you for your patience in replying. My bad that forgot to mention: memory monitors in golang including pprof can not detect this leak. The heap alloc/inuse can not represent the real memory usage by the program. that's why I am using a docker container with docker stats
to monitor the mem usage. could this be a leak on CGO side?
from go-sqlite3.
Related Issues (20)
- Segmentation fault in Ubuntu 18.04 with GLIBC_2.34 HOT 1
- 【ERROR】Windows use winlibs HOT 1
- Panic while using sqlite rows.Next() - fatal error: unexpected signal during runtime execution
- sqlite3-binding.c use after free HOT 4
- Generic PRAGMA URI parameters HOT 9
- Restore in-memory database failed by using Online Backup API HOT 2
- vtable example broken HOT 2
- feature request: sqlar HOT 2
- Fix explicit fallthrough macro
- enable geopoly HOT 2
- Bazel nogo error: unsafeptr
- cost so long time to build HOT 4
- ez
- cross compile error from mac to armv7 HOT 2
- Segmentation Violation HOT 2
- Add Inline Documentation for adding Custom Extension Functions in `sqlite3-binding.c`
- update sqlite to 3.46.1 HOT 1
- DW_FORM_strx with no .debug_str_offsets section HOT 6
- compiling with sqlite_math_functions tag
- program exits with 137 HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from go-sqlite3.