vibe-d / vibe.d

Official vibe.d development
MIT License
1.15k stars 284 forks source link

Memory leaks, vibe.d 0.7.24, win32 #1222

Open alexeibs opened 9 years ago

alexeibs commented 9 years ago

Here is a test program:

import vibe.http.fileserver;
import vibe.http.router : URLRouter;
import vibe.http.server;

__gshared ubyte[] globalBuffer;

void getIndex(HTTPServerRequest request, HTTPServerResponse response) {
  response.render!("index.dt", request);
}

void getImage(HTTPServerRequest request, HTTPServerResponse response) {
  response.contentType = "image/jpeg";
  response.bodyWriter.write(globalBuffer);
}

shared static this() {
  globalBuffer = cast(ubyte[])std.file.read("test.jpg");

  auto router = new URLRouter;
  router.get("/", &getIndex);
  router.get("/image", &getImage);
  router.get("*", serveStaticFiles("./public/"));

  auto settings = new HTTPServerSettings;
  settings.port = 8080;
  listenHTTP(settings, router);
}

index.dt

doctype html
html
  head
    meta(charset='UTF8')
    title DStreamer
  body
    script(type='text/javascript', src='script.js')

script.js

(function () {
  var fpsDiv;
  var index = 0;
  var startTime = +new Date();

  var image = document.createElement('img');
  image.src = '/image';
  image.onload = function() {
    ++index;
    image.src = '/image?n=' + index;
    fpsDiv.innerHTML = index * 1000 / (+new Date() - startTime);
  }
  document.body.appendChild(image);

  fpsDiv = document.createElement('div');
  fpsDiv.style.position = 'absolute';
  fpsDiv.style.overflow = 'hidden';
  fpsDiv.style.left = '10px';
  fpsDiv.style.top = '10px';
  fpsDiv.style.left = '10px';
  fpsDiv.style.width = '60px';
  fpsDiv.style.height = '30px';
  fpsDiv.style.backgroundColor = 'white';
  document.body.appendChild(fpsDiv);

})();

I run it with 1920x1080 jpeg file (~500k). The server crashes quite fast after consuming about 1,5 Gb RAM with this error:

0x0052B285 in _d_assert_msg
0x0041147B in nothrow void vibe.utils.array.AllocAppender!(ubyte[], ubyte).AllocAppender.reserve(uint) at C:\Users\alex\AppData\Roaming\dub\packages\vibe-d-0.7.24\source\vibe\utils\array.d(74)
0x004117E7 in nothrow void vibe.utils.array.AllocAppender!(ubyte[], ubyte).AllocAppender.grow(uint) at C:\Users\alex\AppData\Roaming\dub\packages\vibe-d-0.7.24\source\vibe\utils\array.d(148)
0x004116A5 in nothrow void vibe.utils.array.AllocAppender!(ubyte[], ubyte).AllocAppender.put(ubyte[]) at C:\Users\alex\AppData\Roaming\dub\packages\vibe-d-0.7.24\source\vibe\utils\array.d(105)
0x0041174F in nothrow void vibe.utils.array.AllocAppender!(ubyte[], ubyte).AllocAppender.put(const(ubyte[])) at C:\Users\alex\AppData\Roaming\dub\packages\vibe-d-0.7.24\source\vibe\utils\array.d(112)
0x0045C8C1 in void vibe.http.common.ChunkedOutputStream.write(const(ubyte[])) at C:\Users\alex\AppData\Roaming\dub\packages\vibe-d-0.7.24\source\vibe\http\common.d(461)
etcimon commented 9 years ago

It looks like the GC isn't collecting, what windows version are you using? Maybe you can try a basic allocation test? e.g. running new char[500]; in a loop

Also, try using the scope keyword in your parameters, e.g. scope HTTPServerRequest ...

etcimon commented 9 years ago

I couldn't compile with x86 so I compiled your test with libasync and saw no leaks, can you confirm?

alexeibs commented 9 years ago

OS - Window 7 x64 I replaced this

response.contentType = "image/jpeg";
response.bodyWriter.write(globalBuffer);

by this

response.writeBody(globalBuffer, "image/jpeg");

After that memory usage grows much slower.

etcimon commented 9 years ago

Which version of DMD are you using?

alexeibs commented 9 years ago

DMD 2.068

etcimon commented 9 years ago

Does the following change help?


void getIndex(scope HTTPServerRequest request, scope HTTPServerResponse response) {
  response.render!("index.dt", request);
}

void getImage(scope HTTPServerRequest request, scope HTTPServerResponse response) {
  response.contentType = "image/jpeg";
  response.bodyWriter.write(globalBuffer);
}
alexeibs commented 9 years ago

No, it doesn't. But if I replace getImage code with 'response.writeBody(globalBuffer, "image/jpeg");' it helps a lot. Memory usage still grows but very slowly.