为什么读取输入作为流与字符串的内存效率更高?

时间:2009-12-10 00:51:43

标签: java stream httpclient

我们正在使用HTTPClient来实现REST API。

我们正在使用以下方式阅读服务器响应:

method = new PostMethod(url);
HttpClient client = new HttpClient();
int statusCode = client.executeMethod(method);
String responseBody = method.getResponseBodyAsString();

当我们这样做时,我们会收到此警告:

Dec 9, 2009 7:41:11 PM org.apache.commons.httpclient.HttpMethodBase getResponseBody
WARNING: Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.

docs继续说:

  

HttpClient能够高效   请求/响应正文流。大   可以提交或接收实体   没有缓冲在内存中。这个   如果是多重的话,尤其重要   可以执行HTTP方法   同时。虽然有   方便的处理方法   字符串或字节等实体   数组,不鼓励使用它们。   除非小心使用,否则很容易   导致内存不足的情况,   因为他们意味着缓冲了   内存中的完整实体。

所以我的问题是,如果你确实需要完整的响应作为字符串(即:存储在数据库中,或使用DOM解析),为什么使用流更节省内存?

4 个答案:

答案 0 :(得分:13)

使用流而不是将整个实体作为String更有效,因为后者意味着

  1. 在将响应返回到您的代码之前,需要先阅读响应的全部内容,
  2. 在服务器发送完整响应之前,
  3. 控件无法返回到您的代码。
  4. 如果您将响应作为流处理,那么您实际在做的是一次处理N个字节。这意味着您可以在远程服务器仍在发送下一段数据时开始处理第一个响应段。因此,作为访问方法更有意义如果您的用例允许您在接收数据时处理数据。

    但是,无论出于何种原因,如果你需要将整个响应作为字符串,那么流方法的所有效率都不会对你产生任何影响 - 因为即使你把响应读成碎片,你仍然需要等待完整的响应 - 并且在处理它之前将它全部包含在一个字符串中。

    只有在您拥有可以在拥有整个响应主体之前开始处理响应的用例时,才能使用流的效率。

答案 1 :(得分:4)

整个过程的内存效率并不高。如果您从流中读取并将其放在一个字符串中,您只需将该过程分成两部分,以便HttpClient类不会注意到它。

如果您确实需要整个字符串,则可以忽略该警告。然后由您来确保每个请求不会占用太多内存,这样服务器就不会被DoS攻击轻易打倒。

答案 2 :(得分:1)

你的问题混淆了这一点。

如果您绝对需要将整个响应作为字符串,那么就这样做,

但是如果你可以完全逃脱它,请使用流。

当您将整个响应加载到字符串中时,整个响应主体一次出现在内存中。

使用流,一次只有一小部分响应保存在内存中。

文档说,特别是对于多个大型请求,将整个请求主体加载到字符串中需要大量内存。

答案 3 :(得分:0)

如果您正在解析为org.w3c.Document(或者更好,还有org.jdom.Document),那么直接使用该流非常容易。例如:

org.apache.http.HttpResponse hr = httpClient.execute(httpRequest);
org.apache.http.HttpEntity he = hr.getEntity();
org.jdom.input.SAXBuilder builder = new SAXBuilder();
org.jdom.Document document = builder.build(he.getContent());