heap - Dart HttpServer 耗尽堆空间

标签 heap dart httpserver

我一直在修改一些示例代码以用于 Web 服务器,这样我就可以在服务器和客户端上运行 dart。但是,我决定要检查 Web 服务器的性能,除了崩溃之外,我印象最深刻。我在 Ubuntu 上使用“siege”包,使用少量 URL 为网站生成大量流量。

我已经看到它每秒传输 1000 个事务,这对我来说是非常可接受的,但是在运行两到三分钟后,它要么崩溃要么挂起(如果我增加 new_gen_heap_size)。

#import('dart:io');

class FCServer {

String basePath;

void send404(HttpResponse response)
{
    response.statusCode = HttpStatus.NOT_FOUND;
    response.outputStream.close();
}

void handleRequest(HttpRequest request, HttpResponse response)
{
  final String path = request.path == '/' ? '/index.html' : request.path;
  final File file = new File('${basePath}${path}');
  file.exists().then((bool found) {
      if (found)
      {
          file.fullPath().then((String fullPath) {
              if (!fullPath.startsWith(basePath))
              {
                  send404(response);
              }
              else
              {
                  //print("delivering $fullPath");
                  response.headers.add("Cache-Control", "max-age=3600");
                  //file.openInputStream().pipe(response.outputStream);
                  var file = new File("$fullPath");
                  //response.headers.set(HttpHeaders.CONTENT_TYPE, "$contentType; charset=UTF-8");
                  response.outputStream.write(file.readAsBytesSync());
                  response.outputStream.close();
              }
         });
        }
        else
        {
            send404(response);
        }
    }); 
}

void startServer(String basePath)
{
    this.basePath = basePath;
    var server = new HttpServer();
    print("Starting server with basePath: $basePath");
    server.listen('192.168.0.14', 8080);
    server.listen('127.0.0.1', 8080);
    server.defaultRequestHandler = handleRequest;
}
}

FCServer webServe;
main()
{
    // Compute base path for the request based on the location of the
    // script and then start the server.
    webServe = new FCServer();
    File script = new File(new Options().script);
    script.directory().then((Directory d) {
        webServe.startServer(d.path);
    });
}

Dart退出前打印的错误如下:
Exhausted heap space, trying to allocate 128096 bytes.
Exhausted heap space, trying to allocate 112 bytes.
Exception 'Instance of 'OutOfMemoryException'' thrown:
Exiting the process

这是否意味着某处存在内存泄漏?或者有人可以解释发生了什么?

编辑:当 new_gen_heap_size 增加到 1024 时,它会在一段时间后挂起,并且无论请求是否传入,单个线程都处于 100%。此时,在使用上述堆大小运行后,RAM 高达 1.5GB,所以我假设垃圾收集器已经踢了桶,可以这么说。

编辑 2:我修改了代码,以便在初始化时创建一个由 4 个字节组成的列表,然后每次发出请求时,它都会将该列表写入响应并关闭响应。内存使用量仍在快速增长,表明 Dart 内部存在更深层次的问题。这让我厌倦了在一个完整的项目中使用 Dart。

最佳答案

你为什么注释掉“file.openInputStream().pipe(response.outputStream);”并将其替换为“response.outputStream.write(file.readAsBytesSync());”?这样做存在三个问题:

  • 完成读取文件后,它不会关闭文件。
  • 它不是异步的。
  • 它同时读取所有字节,而不是将它们流式传输到客户端。

  • 如果您碰巧正在处理一个非常大的文件,并且您有大量并发请求,那么您将在内存中拥有该文件的大量副本。

    是否使用“file.openInputStream().pipe(response.outputStream);”让问题消失?

    我有信心“response.outputStream.write(file.readAsBytesSync());”是问题所在。另外,请记住 .write 不会立即写入字节。它缓冲它们以供写入。因此,您有一个缓冲的整个文件的副本以供写入。

    更新 :Mads Ager 确认这是内存泄漏,并且他已经提交了修复程序。 Here's the bug他提出。

    关于heap - Dart HttpServer 耗尽堆空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13188127/

    相关文章:

    二叉堆的 C++ 实现

    java - 在 gs-collections 库中寻找排序堆和并发队列

    windows - 如何在 Dart SDK 的 Windows 中以字符串形式获取路径而无需前导 "slash"?

    flutter - 为什么直接在Column中使用ListView会导致呈现错误?

    node.js - 在node.js上运行的HTTP服务器中如何仅用一小块空间来表示连接?

    delphi - 如何在控制台应用程序中创建独立的 HTTPServer

    python - python中的最小堆

    forms - 如何验证值更改的文本字段?

    Angular 5 修复 Assets /文件夹的相对路径

    algorithm - 仅使用堆从任意整数数组中查找中位数