fasthttprouter icon indicating copy to clipboard operation
fasthttprouter copied to clipboard

Router allocates on the heap

Open erikdubbelboer opened this issue 8 years ago • 1 comments

Because the router is converting bytes slices to strings it allocates memory on the heap for each request.

This can be prevented by casting the slice to a string. ~The downside of this approach is that the UserValues will only be valid during the request as after the request they will change when the next request reuses the memory. It also means that changing the UserValue will change the request URI as well.~ This doesn't seem to be true.

diff --git a/router.go b/router.go
index 57c6e13..4e8fac9 100644
--- a/router.go
+++ b/router.go
@@ -75,6 +75,7 @@ package fasthttprouter
 
 import (
        "strings"
+       "unsafe"
 
        "github.com/valyala/fasthttp"
 )
@@ -293,8 +294,8 @@ func (r *Router) Handler(ctx *fasthttp.RequestCtx) {
                defer r.recv(ctx)
        }
 
-       path := string(ctx.Path())
-       method := string(ctx.Method())
+       path := b2s(ctx.Path())
+       method := b2s(ctx.Method())
        if root := r.trees[method]; root != nil {
                if f, tsr := root.getValue(path, ctx); f != nil {
                        f(ctx)
@@ -372,3 +373,12 @@ func (r *Router) Handler(ctx *fasthttp.RequestCtx) {
                        fasthttp.StatusNotFound)
        }
 }
+
+// b2s converts byte slice to a string without memory allocation.
+// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
+//
+// Note it may break if string and/or slice header will change
+// in the future go versions.
+func b2s(b []byte) string {
+       return *(*string)(unsafe.Pointer(&b))
+}

erikdubbelboer avatar Jun 03 '17 04:06 erikdubbelboer

Ooops, didn't see this issue but prepared a pull request: https://github.com/buaazp/fasthttprouter/pull/51

(in my tests and build with gcflags="-m -m" the method variable didn't escape)

gallir avatar Apr 07 '19 02:04 gallir