我有以下http处理程序代码,在后续请求中从Amazon S3下载原始图像并将其转换为所需的宽高比并将其保存在s3上。这段代码泄漏了内存,并在一段时间后崩溃。我已经处理了所有内容,并对代码进行了分析。但是,仍然无法弄清楚这个问题。如果有人能在这里弄清楚,将不胜感激。仅供参考,我使用的是go version go1.5.3 linux/amd64
版本。
分析输出
3259.27kB of 3302.42kB total (98.69%)
Dropped 258 nodes (cum <= 16.51kB)
Showing top 30 nodes out of 91 (cum >= 27.76kB)
flat flat% sum% cum cum%
1552.59kB 47.01% 47.01% 1552.59kB 47.01% bytes.makeSlice
584kB 17.68% 64.70% 584kB 17.68% imagick._Cfunc_GoBytes
257.38kB 7.79% 72.49% 257.38kB 7.79% encoding/pem.Decode
168.11kB 5.09% 77.58% 168.11kB 5.09% crypto/tls.(*block).reserve
165.09kB 5.00% 82.58% 389.49kB 11.79% crypto/x509.parseCertificate
105.32kB 3.19% 85.77% 105.32kB 3.19% reflect.unsafe_NewArray
83.64kB 2.53% 88.30% 83.64kB 2.53% math/big.nat.make
75.55kB 2.29% 90.59% 75.55kB 2.29% net/http.(*Transport).dialConn
64.02kB 1.94% 92.53% 64.02kB 1.94% regexp.(*bitState).reset
43.77kB 1.33% 93.85% 43.77kB 1.33% crypto/x509.(*CertPool).AddCert
40.44kB 1.22% 95.08% 40.44kB 1.22% crypto/x509/pkix.(*Name).FillFromRDNSequence
40.16kB 1.22% 96.29% 40.16kB 1.22% encoding/asn1.parsePrintableString
24.07kB 0.73% 97.02% 24.07kB 0.73% net/http.newBufioWriterSize
18.98kB 0.57% 97.60% 18.98kB 0.57% net/http.newBufioReader
16.14kB 0.49% 98.09% 64.77kB 1.96% crypto/tls.(*Conn).readHandshake
12.01kB 0.36% 98.45% 237.09kB 7.18% encoding/asn1.parseField
8.01kB 0.24% 98.69% 91.65kB 2.78% crypto/x509.parsePublicKey
0 0% 98.69% 112.33kB 3.40% bufio.(*Reader).Read
0 0% 98.69% 80.32kB 2.43% bufio.(*Reader).fill
0 0% 98.69% 27.76kB 0.84% bufio.(*Writer).ReadFrom
0 0% 98.69% 27.76kB 0.84% bufio.(*Writer).flush
0 0% 98.69% 1648.33kB 49.91% bytes.(*Buffer).ReadFrom
0 0% 98.69% 16.59kB 0.5% bytes.(*Buffer).Write
0 0% 98.69% 16.59kB 0.5% bytes.(*Buffer).grow
0 0% 98.69% 843.06kB 25.53% crypto/tls.(*Conn).Handshake
0 0% 98.69% 112.33kB 3.40% crypto/tls.(*Conn).Read
0 0% 98.69% 27.76kB 0.84% crypto/tls.(*Conn).Write
0 0% 98.69% 843.06kB 25.53% crypto/tls.(*Conn).clientHandshake
0 0% 98.69% 160.96kB 4.87% crypto/tls.(*Conn).readRecord
0 0% 98.69% 27.76kB 0.84% crypto/tls.(*Conn).writeRecord
代码:
func main() {
imagick.Initialize()
defer imagick.Terminate()
myMux := http.NewServeMux()
myMux.HandleFunc("/", serveHTTP)
if err := http.ListenAndServe(":8082", myMux); err != nil {
logFatal("Error when starting or running http server: %v", err)
}
}
func serveHTTP(w http.ResponseWriter, r *http.Request) {
var isMaster bool = true
var desiredAspectRatio float64 = 1.77
if r.RequestURI == "/favicon.ico" {
w.WriteHeader(http.StatusNotFound)
return
}
if len(strings.TrimSpace(r.URL.Query().Get("ar"))) != 0 {
desiredAspectRatio, _ = strconv.ParseFloat(r.URL.Query().Get("ar"), 64)
}
if len(strings.TrimSpace(r.URL.Query().Get("ism"))) != 0 {
isMaster, _ = strconv.ParseBool(r.URL.Query().Get("ism"))
}
imageUrl := strings.ToLower(r.URL.Path[1:])
isProcessed := CreateMaster(imageUrl, desiredAspectRatio, isMaster)
if isProcessed == false {
w.WriteHeader(http.StatusNotFound)
return
}
if !sendResponse(w, r, imageUrl) {
// w.WriteHeader() is skipped intentionally here, since the response may be already partially created.
return
}
logRequestMessage(r, "SUCCESS")
}
func sendResponse(w http.ResponseWriter, r *http.Request, imageUrl string) bool {
w.Header().Set("Content-Type", "text/plain")
if _, err := w.Write([]byte("master created")); err != nil {
logRequestError(r, "Cannot send image from imageUrl=%v to client: %v", imageUrl, err)
return false
}
return true
}
func CreateMaster(keyName string, desiredAspectRatio float64, isMaster bool) bool {
s3Client := s3.New(session.New(), &aws.Config{Region: aws.String(region)})
params := &s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(keyName),
}
fmt.Println(" Master creation request for key : " + keyName)
out, err := s3Client.GetObject(params)
if err != nil {
return false
}
defer out.Body.Close()
img, err := ioutil.ReadAll(out.Body)
if err != nil {
return false
}
mw := imagick.NewMagickWand()
defer mw.Destroy()
err = mw.ReadImageBlob(img)
if err != nil {
return false
}
if isMaster == false {
paramsPut := &s3.PutObjectInput{
Bucket: aws.String(masterBucketName),
Key: aws.String(keyName),
Body: bytes.NewReader(mw.GetImageBlob()),
}
_, err = s3Client.PutObject(paramsPut)
if err != nil {
log.Printf("Couldn't put the image on s3 : " + keyName + "%s\n", err)
}
return true
}
originalWidth := float64(mw.GetImageWidth())
originalHeight := float64(mw.GetImageHeight())
imageAspectRatio := originalWidth / originalHeight
masterWidth := cwMasterWidth
masterHeight := cwMasterHeight
masterAspectRatio := math.Trunc((cwMasterWidth / cwMasterHeight) * 100)/100
if masterAspectRatio != desiredAspectRatio {
masterAspectRatio = desiredAspectRatio
}
pwm := imagick.NewPixelWand()
defer pwm.Destroy()
tx := imagick.NewMagickWand()
defer tx.Destroy()
if isMaster == true {
var w, h uint = 0, 0
size := fmt.Sprintf("%dx%d^+0+0", w, h)
if imageAspectRatio <= masterAspectRatio {
// trim the height
w = uint(originalWidth)
h = (uint(originalWidth / masterAspectRatio))
size = fmt.Sprintf("%dx%d^+0+0", w, h)
} else {
// trim the width
w = uint(originalHeight * masterAspectRatio)
h = uint(originalHeight)
size = fmt.Sprintf("%dx%d^+0+0", w, h)
}
tx = mw.TransformImage("", size)
tx.SetImageGravity(imagick.GRAVITY_CENTER)
offsetX := -(int(w) - int(tx.GetImageWidth())) / 2
offsetY := -(int(h) - int(tx.GetImageHeight())) / 2
err := tx.ExtentImage(w, h, offsetX, offsetY)
if float64(tx.GetImageWidth()) > masterWidth && float64(tx.GetImageHeight()) > masterHeight {
err = tx.ResizeImage(uint(masterWidth), uint(masterHeight), imagick.FILTER_BOX, 1)
if err != nil {
log.Printf("Inside CreateMaster function Couldn't resize the image : " + keyName + "%s\n", err)
return false
}
}
}
paramsPut := &s3.PutObjectInput{
Bucket: aws.String(masterBucketName),
Key: aws.String(keyName),
Body: bytes.NewReader(tx.GetImageBlob()),
}
_, err = s3Client.PutObject(paramsPut)
if err != nil {
log.Printf("Inside CreateMaster function Couldn't put the image on s3 : " + keyName + "%s\n", err)
return false
}
return true
}
答案 0 :(得分:3)
你正在泄漏一根魔杖。
在这里,您分配一个新的魔杖并将其推迟销毁:
tx := imagick.NewMagickWand()
defer tx.Destroy()
但是接下来,在“if”块中,你用从TransformImage()
调用返回的魔杖替换它:
tx = mw.TransformImage("", size)
tx.SetImageGravity(imagick.GRAVITY_CENTER)
如果你完全摆脱了新魔法棒的第一次分配,并且只是确保Destroy()
从TransformImage()
返回新的魔杖,那么泄漏就会消失。
参考issue tracker, #72,了解详情