http.Response.Body复制导致大量内存使用量增加

时间:2015-09-08 05:47:34

标签: go

所以我试图从http.Response中获取响应主体,进行一些操作,然后将其设置回来。这是我第一次尝试将其删除而不会耗尽http.Response:

<?php

$username = 'username'; 
$password = 'pass'; 
$host = 'localhost'; 
$dbname = 'db';


try {
 $dbh = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
 // set the PDO error mode to exception
 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

 $stmt = $dbh->prepare("INSERT INTO table1 (issue, time, comments, lat, lng) VALUES (:issue, :time, :comments, :lat, :lng)");
    $stmt->bindParam(':issue', $issue);
    $stmt->bindParam(':time', $time);
    $stmt->bindParam(':comments', $comments);
    $stmt->bindParam(':lat', $lat);
    $stmt->bindParam(':lng', $lng);

    $stmt->execute();

        header("Location: main.php");

 }
catch(PDOException $e)
    {
    echo "Error: " . $e->getMessage();
    }
$dbh = null;



?>

如果我发送500个请求,响应大小为1mb(一大块JSON,但它可能是任何格式,不仅是JSON),服务器内存使用量上升到〜400mb,并且不会回来了。这是正常的吗?上面的代码有问题吗?我错过了释放记忆的东西吗?

延迟resp.Body.Close()无效。

谢谢!

编辑1

这里有一个简单版本的代理,包括建议的近距离通话。如果localhost:3000(它代理的位置)的服务器返回大响应,则内存使用量将迅速增加。就我而言,我正在返回一个1mb的json文件,并通过go代理发送500个请求会将内存使用量增加到大约400mb。

go代理:
https://gist.github.com/marbemac/300c4c376171cbd27cc3

一个简单的节点服务器,它返回名为large_response.json的同一目录中的文件 https://gist.github.com/marbemac/55aaa78f5858484d33f6

2 个答案:

答案 0 :(得分:3)

使用后必须关闭身体。请参阅this

请注意,在您使用新值重新分配defer resp.Body.Close()后,系统会调用resp.Body

答案 1 :(得分:2)

ioutil.NopCloser使Close()无所作为。如果你推迟关闭,你永远不会真正关闭它。在阅读后立即关闭。

bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
    // err
} 
resp.Body.Close()
cachedBody := string(bodyBytes)
// Close() does nothing after this
resp.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))

同样在Go中,您通常可以忽略该else,因为您可能应该返回错误或在其上方if处理错误。

这样的事情也很适合拥有sync.Pool,因为你继续回收大量的缓冲区,检查它在net/http包中的使用方式。