[lxc-devel] [lxd/master] GC improvements

stgraber on Github lxc-bot at linuxcontainers.org
Fri Jun 1 04:04:13 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180601/f6245061/attachment.bin>
-------------- next part --------------
From d70c1385eba7aeeabf7546bccc22ad6076dcf6bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 31 May 2018 23:51:32 -0400
Subject: [PATCH 1/2] Manually release the liblxc structs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/container_lxc.go | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 6c008abae..aadde3e56 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -13,6 +13,7 @@ import (
 	"path"
 	"path/filepath"
 	"reflect"
+	"runtime"
 	"sort"
 	"strconv"
 	"strings"
@@ -466,6 +467,9 @@ func containerLXCLoad(s *state.State, args db.ContainerArgs) (container, error)
 	// Create the container struct
 	c := containerLXCInstantiate(s, args)
 
+	// Setup finalizer
+	runtime.SetFinalizer(c, containerLXCUnload)
+
 	// Load the config.
 	err := c.init()
 	if err != nil {
@@ -475,6 +479,15 @@ func containerLXCLoad(s *state.State, args db.ContainerArgs) (container, error)
 	return c, nil
 }
 
+// Unload is called by the garbage collector
+func containerLXCUnload(c *containerLXC) {
+	runtime.SetFinalizer(c, nil)
+	if c.c != nil {
+		lxc.Release(c.c)
+		c.c = nil
+	}
+}
+
 // Create a container struct without initializing it.
 func containerLXCInstantiate(s *state.State, args db.ContainerArgs) *containerLXC {
 	return &containerLXC{
@@ -7166,6 +7179,8 @@ func (c *containerLXC) fillNetworkDevice(name string, m types.Device) (types.Dev
 		// Attempt to include all existing interfaces
 		cc, err := lxc.NewContainer(c.Name(), c.state.OS.LxcPath)
 		if err == nil {
+			defer lxc.Release(cc)
+
 			interfaces, err := cc.Interfaces()
 			if err == nil {
 				for _, name := range interfaces {
@@ -7423,6 +7438,7 @@ func (c *containerLXC) removeNetworkDevice(name string, m types.Device) error {
 	if err != nil {
 		return err
 	}
+	defer lxc.Release(cc)
 
 	// Remove the interface from the container
 	err = cc.DetachInterfaceRename(m["name"], hostName)

From 88073c1168675d58bb5cb3c48e8b8572a256c477 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 31 May 2018 16:53:05 -0400
Subject: [PATCH 2/2] Drop manual GC calls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The GC has come a long way since we had to add those calls to avoid fd
leaks when getting rid of references to the lxc struct.

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/daemon.go     | 13 -------------
 lxd/operations.go | 13 -------------
 2 files changed, 26 deletions(-)

diff --git a/lxd/daemon.go b/lxd/daemon.go
index a0342dcb4..d1a30fcfb 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -11,7 +11,6 @@ import (
 	"net/url"
 	"os"
 	"path/filepath"
-	"runtime"
 	"strings"
 	"sync"
 	"syscall"
@@ -318,18 +317,6 @@ func (d *Daemon) createCmd(restAPI *mux.Router, version string, c Command) {
 				logger.Errorf("Failed writing error for error, giving up")
 			}
 		}
-
-		/*
-		 * When we create a new lxc.Container, it adds a finalizer (via
-		 * SetFinalizer) that frees the struct. However, it sometimes
-		 * takes the go GC a while to actually free the struct,
-		 * presumably since it is a small amount of memory.
-		 * Unfortunately, the struct also keeps the log fd open, so if
-		 * we leave too many of these around, we end up running out of
-		 * fds. So, let's explicitly do a GC to collect these at the
-		 * end of each request.
-		 */
-		runtime.GC()
 	})
 }
 
diff --git a/lxd/operations.go b/lxd/operations.go
index 466e28896..849256ed2 100644
--- a/lxd/operations.go
+++ b/lxd/operations.go
@@ -3,7 +3,6 @@ package main
 import (
 	"fmt"
 	"net/http"
-	"runtime"
 	"strings"
 	"sync"
 	"time"
@@ -100,18 +99,6 @@ func (op *operation) done() {
 		if err != nil {
 			logger.Warnf("Failed to delete operation %s: %s", op.id, err)
 		}
-
-		/*
-		 * When we create a new lxc.Container, it adds a finalizer (via
-		 * SetFinalizer) that frees the struct. However, it sometimes
-		 * takes the go GC a while to actually free the struct,
-		 * presumably since it is a small amount of memory.
-		 * Unfortunately, the struct also keeps the log fd open, so if
-		 * we leave too many of these around, we end up running out of
-		 * fds. So, let's explicitly do a GC to collect these at the
-		 * end of each request.
-		 */
-		runtime.GC()
 	})
 }
 


More information about the lxc-devel mailing list