Dart HttpServer耗尽堆空间

kmbjn2e3  于 2022-12-27  发布在  其他
关注(0)|答案(1)|浏览(139)

我已经修改了一些示例代码来用于网络服务器,这样我就可以让dart同时在服务器和客户端运行。然而,我决定检查一下网络服务器的性能,除了崩溃之外,我印象最深刻的是。我正在使用Ubuntu上的“围攻”包,使用少量的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字节的List,然后每次发出请求时,它只会将该List写入响应并关闭响应。内存使用量仍然快速增长,表明Dart内部存在更深层次的问题。这让我厌倦了在全面项目中使用Dart。

ctrmrzij

ctrmrzij1#

为什么要注解掉“file.openInputStream().pipe(response.outputStream);“并将其替换为“响应.输出流.写入(文件.读取AsBytesSync());“?这有三个问题:

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

如果您碰巧要处理一个非常大的文件,并且有大量并发请求,那么内存中就会有该文件的大量副本。
使用“文件.openInputStream().管道(响应.输出流);“让问题消失?
我对“响应.输出流.写入(文件.读取AsBytesSync());“是问题所在。另外,请记住,.write不会立即写入字节。它会缓冲这些字节以备写入。因此,您有一个缓冲的整个文件的副本以备写入。

更新日期:Mads Ager验证了这是一个内存泄漏,他已经提交了一个修复程序。

相关问题