Skip to content

Commit e799f2a

Browse files
authored
Merge pull request #29 from Oppen/public_free
Add public free method
2 parents 78e9e71 + 6118dd3 commit e799f2a

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

free_test/explicit_free.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"runtime"
7+
"syscall"
8+
9+
"github.com/RoaringBitmap/gocroaring"
10+
)
11+
12+
// Exits with code 0 on success, 1 on test failure
13+
// or 2 on program failure (e.g. OOM or syscall error).
14+
15+
func main() {
16+
const (
17+
N = 10000
18+
M = 10000
19+
)
20+
21+
var rusage syscall.Rusage
22+
var maxrss_0, maxrss_free, maxrss_gc int64
23+
24+
fmt.Printf("Starting execution... ")
25+
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
26+
fmt.Printf("Getrusage failed with error: %s\n", err)
27+
os.Exit(2)
28+
}
29+
maxrss_0 = rusage.Maxrss
30+
fmt.Printf("max RSS: %d bytes\n", maxrss_0)
31+
32+
bitmap := gocroaring.New()
33+
for i := uint32(0); i < M; i++ {
34+
bitmap.Add(i*10)
35+
}
36+
fmt.Printf("Created reference bitmap... ")
37+
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
38+
fmt.Printf("Getrusage failed with error: %s\n", err)
39+
os.Exit(2)
40+
}
41+
fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)
42+
43+
bitmaps := make([]*gocroaring.Bitmap, N)
44+
fmt.Printf("Allocated slice for %d bitmap pointers... ", N)
45+
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
46+
fmt.Printf("Getrusage failed with error: %s\n", err)
47+
os.Exit(2)
48+
}
49+
maxrss_free = rusage.Maxrss
50+
fmt.Printf("max RSS: %d bytes\n", maxrss_free)
51+
52+
for i := range bitmaps {
53+
bitmaps[i] = bitmap.Clone()
54+
bitmaps[i].Free()
55+
}
56+
fmt.Printf("Copied then explicitly freed %d bitmaps... ", N)
57+
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
58+
fmt.Printf("Getrusage failed with error: %s\n", err)
59+
os.Exit(2)
60+
}
61+
fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)
62+
63+
bitmaps = nil
64+
runtime.GC()
65+
fmt.Printf("GC'd old bitmaps... ")
66+
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
67+
fmt.Printf("Getrusage failed with error: %s\n", err)
68+
os.Exit(2)
69+
}
70+
fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)
71+
72+
bitmaps = make([]*gocroaring.Bitmap, N)
73+
fmt.Printf("Allocated slice for %d bitmap pointers... ", N)
74+
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
75+
fmt.Printf("Getrusage failed with error: %s\n", err)
76+
os.Exit(2)
77+
}
78+
fmt.Printf("max RSS: %d bytes\n", rusage.Maxrss)
79+
80+
for i := range bitmaps {
81+
bitmaps[i] = bitmap.Clone()
82+
}
83+
bitmaps = nil
84+
runtime.GC()
85+
fmt.Printf("Copied then GC'd %d bitmaps... ", N)
86+
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
87+
fmt.Printf("Getrusage failed with error: %s\n", err)
88+
os.Exit(2)
89+
}
90+
maxrss_gc = rusage.Maxrss
91+
fmt.Printf("max RSS: %d bytes\n", maxrss_gc)
92+
93+
ballpark_free := maxrss_free - maxrss_0
94+
ballpark_gc := maxrss_gc - maxrss_0
95+
fmt.Printf("Used ~%d bytes with explicit free\n", ballpark_free)
96+
fmt.Printf("Used ~%d bytes without explicit free\n", ballpark_gc)
97+
98+
if ballpark_gc < 100*ballpark_free {
99+
fmt.Printf("Expected a much greater difference!\n")
100+
os.Exit(1)
101+
}
102+
}

gocroaring.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ func New(x ...uint32) *Bitmap {
5454
return answer
5555
}
5656

57+
func (rb *Bitmap) Free() {
58+
// Clear the finalizer to avoid double frees
59+
runtime.SetFinalizer(rb, nil)
60+
free(rb)
61+
}
62+
5763
// Printf writes a description of the bitmap to stdout
5864
func (rb *Bitmap) Printf() {
5965
fmt.Print("{")

gocroaring_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package gocroaring
33
import (
44
"fmt"
55
"math/rand"
6+
"os/exec"
67
"reflect"
78
"runtime"
89
"testing"
@@ -57,6 +58,14 @@ func TestMemoryUsage(t *testing.T) {
5758
}
5859
}
5960

61+
func TestExplicitFree(t *testing.T) {
62+
output, err := exec.Command("go", "run", "free_test/explicit_free.go").Output()
63+
if err != nil {
64+
t.Errorf("Command exited with error: %s", err)
65+
}
66+
fmt.Printf("TestExplicitFree output:\n%s\n", output)
67+
}
68+
6069
func TestSimpleCard(t *testing.T) {
6170
bitmap := New()
6271
for i := 100; i < 1000; i++ {

0 commit comments

Comments
 (0)