Dart HttpServer Exhausts Heap Space

I modified some sample code to use for the web server, so I can start the dart on the server and on the client. However, I decided that I wanted to test the performance of the web server, and I was mostly impressed, except for the crashes. I use the siege package on Ubuntu to generate a lot of traffic on a website using multiple URLs.

I saw that it delivered a little north of 1000 transactions per second, which is very acceptable for me, but after two to three minutes of operation it either crashes or freezes (if I increase 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); }); } 

The error that Dart prints before exiting is as follows:

 Exhausted heap space, trying to allocate 128096 bytes. Exhausted heap space, trying to allocate 112 bytes. Exception 'Instance of 'OutOfMemoryException'' thrown: Exiting the process 

Does this mean that somewhere there is a memory leak? Or can someone explain what is happening?

EDIT: when new_gen_heap_size is increased to 1024, it hangs after a while, and one thread is at 100%, regardless of whether requests are coming in or not. At this point, RAM reaches 1.5 GB after a run with the above heap size, so I guess the garbage collector kicked the bucket for so long.

EDIT 2: I changed the code so that during initialization it creates a list of 4 bytes, and then every time the request is executed, it simply writes this list to the response and closes the response. Memory usage is still growing rapidly, indicating a problem deeper in Dart. It makes me tired of using Darth for a full-blown project.

+4
source share
1 answer

Why did you comment out "file.openInputStream (). Pipe (response.outputStream);" and replace it with "response.outputStream.write (file.readAsBytesSync ());"? There are three problems with this:

  • It does not close the file when it reads it.
  • It is not asynchronous.
  • It reads all bytes at the same time, and does not pass them to the client.

If you use a really large file and you have a lot of simultaneous requests, you will have many copies of this file in memory.

Uses "file.openInputStream (). Pipe (response.outputStream);" to solve a problem?

I am sure that "response.outputStream.write (file.readAsBytesSync ()); this is a problem. Also, remember that .write does not write bytes at once. It buffers them so that they can be written. Therefore, you have a copy the entire file buffered for writing.

Updated : Mads Ager confirmed that it was a memory leak, and he has already submitted a fix. Here is the mistake he filed.

+4
source

Source: https://habr.com/ru/post/1443563/


All Articles