Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix memory leak(#151) #168

Closed
wants to merge 3 commits into from
Closed

fix memory leak(#151) #168

wants to merge 3 commits into from

Conversation

m-ohuchi
Copy link

#151

I could fix this memory leak. Please review and improve my code if necessary(Especially I think the timing to free the memory is unusual).
With this fix, I make sure the memory leak is disappeared using the test tool by @deepakprabhakara as follows:

result of original code

$ ./node --trace_gc --max_executable_size=8 nano.js 
[8643:0xa09a738]       16 ms: Scavenge 1.7 (2.5) -> 1.6 (3.5) MB, 1.8 / 0.0 ms [allocation failure].
[8643:0xa09a738]       19 ms: Scavenge 1.6 (3.5) -> 1.6 (4.5) MB, 1.7 / 0.0 ms [allocation failure].
...
[8643:0xa09a738]  1051936 ms: Mark-sweep 23.4 (27.5) -> 23.2 (27.5) MB, 34.1 / 3.0 ms (+ 110.5 ms in 55 steps since start of marking, biggest step 9.4 ms) [GC interrupt] [GC in old space requested].
-------- <LEAK> -------
{"growth":15882648,"reason":"heap growth over 5 consecutive GCs (13m 8s) - 69.2 mb/hr"}
-------- </LEAK> -------
...
[8643:0xa09a738]  4728198 ms: Mark-sweep 94.0 (100.5) -> 93.1 (100.5) MB, 155.2 / 6.5 ms (+ 355.3 ms in 166 steps since start of marking, biggest step 35.9 ms) [GC interrupt] [GC in old space requested].
-------- <LEAK> -------
{"growth":17302520,"reason":"heap growth over 5 consecutive GCs (15m 9s) - 65.35 mb/hr"}
-------- </LEAK> -------
...
(the heap allocation size keep increasing.)

result of fixed code

$ ./node --trace_gc --max_executable_size=8 nano.js
[9757:0xa8ac738]       16 ms: Scavenge 1.7 (2.5) -> 1.6 (3.5) MB, 1.2 / 0.0 ms [allocation failure].
[9757:0xa8ac738]       17 ms: Scavenge 1.6 (3.5) -> 1.6 (4.5) MB, 1.1 / 0.0 ms [allocation failure].
...
[9757:0xa8ac738]  1053811 ms: Scavenge 5.7 (8.5) -> 4.9 (8.5) MB, 3.5 / 1.1 ms [allocation failure].
...
[9757:0xa8ac738]  2230825 ms: Scavenge 8.9 (11.5) -> 8.1 (11.5) MB, 6.3 / 1.5 ms [allocation failure].
[9757:0xa8ac738]  2238570 ms: Mark-sweep 8.9 (11.5) -> 3.2 (8.5) MB, 13.0 / 1.3 ms [allocation failure] [promotion limit reached].
[9757:0xa8ac738]  2245874 ms: Scavenge 4.0 (8.5) -> 3.2 (8.5) MB, 2.9 / 1.1 ms [allocation failure].
...
[9757:0xa8ac738]  5207302 ms: Scavenge 12.1 (15.5) -> 11.3 (15.5) MB, 6.7 / 1.4 ms [allocation failure].
[9757:0xa8ac738]  5215005 ms: Mark-sweep 12.1 (15.5) -> 3.1 (8.5) MB, 9.9 / 1.2 ms (+ 8.5 ms in 18 steps since start of marking, biggest step 2.1 ms) [GC interrupt] [GC in old space requested].
...
(the heap allocation size is reset to 3.1~3.2 MB every time when the Mark-sweep GC occurred.)

Add codes to free context to fix the memory leak discussed at #151.

  • Replace uv_poll_stop with uv_close to unref the poll_handler
  • Add mutexs to PollStop to guard asynchronous invocation by the end
    of flush operation and synchronous invocation by close operation
  • Call free(context) to free memory of struct context
  • Execute above free operation when they are called twice using mutexes
    to guarantee the memory is to be freed at last. Because
    wrap_pointer_cb called by GC and the latter part of uv_close
    (and close_cb) will be called asynchronously and disorderly.

Add codes to free context to fix the memory leak discussed at #151.
- Replace uv_poll_stop with uv_close to unref the poll_handler
- Add mutexs to PollStop to guard asynchronous invocation by the end
  of flush operation and synchronous invocation by close operation
- Call free(context) to free memory of struct context
- Execute above free operation when they are called twice using mutexes
  to guarantee the memory is to be freed at last. Because
  wrap_pointer_cb called by GC and the latter part of uv_close
  (and close_cb) will be called asynchronously and disorderly.
@reqshark
Copy link
Collaborator

I think the timing to free the memory is unusual

agreed. also still reviewing your fix this week

cc @nickdesaulniers @kkoopa

@nickdesaulniers
Copy link
Owner

also proof of memory leak fixes, maybe some test code and a graph that shows the memory usage before+after the patch

@reqshark
Copy link
Collaborator

• confidence in our test suite can run without deadlocking

IMO the test failed partially b/c subscription shutdown is known to be brittle

• estimated perf hit of these added synchronizations

yes, +1, although it's intersting that libnanomsg uses global lock operations

also proof of memory leak fixes, maybe some test code and a graph that shows the memory usage before+after the patch

best to observe that kind of thing against long running processes, so i'll update w/ my findings later this week

@reqshark
Copy link
Collaborator

Any chance we can start using C++11?

sure, but i'd rather have C11 than C++11...

C language should be plenty to do whatever we want. also i have nothing against C++11

@nickdesaulniers
Copy link
Owner

nickdesaulniers commented Dec 14, 2016

key takeaways are the leaks are from missing free/deletes to match new Nan::Callback and calloc calls.

- apply clang-format following instruction at README.md
- move uv_mutex_unlock and info.GetReturnValue().Set() to the end of PollStop
  because they are duplicated in both if and else scopes
- move bool variables to the end of struct and remove typedef
- remove all inline decorators and move functions in the header to the source file.
@m-ohuchi
Copy link
Author

I have updated the code with comments by @nickdesaulniers. Please review them again.

In addition to the commit log:

  • I delete unused WrapPointer and UnWrapPointer functions because the compiler have started to warn them when I remove inline decorators.
  • I cannot come up with an idea how to implement RAII to free_context() function in C. Notice me if you have any idea.

@@ -113,7 +113,7 @@ NAN_METHOD(Send) {

void fcb(char *data, void *hint) {
nn_freemsg(data);
(void) hint;
(void)hint;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

void fcb(char *data, void *) {
  nn_freemsg(data);
}


// this function is called asynchronously at destructor when garbage collection
// is executed
static void wrap_pointer_cb(char *data, void *hint) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static void wrap_pointer_cb(char *data, void *) {


template <typename Type>
static Type UnwrapPointer(v8::Local<v8::Value> buffer) {
return reinterpret_cast<Type>(UnwrapPointer(buffer));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer static_cast

// this function is called asynchronously after uv_close function call
void close_cb(uv_handle_t *handle) {
nanomsg_socket_s *context =
reinterpret_cast<nanomsg_socket_s *>(handle->data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer static_cast

uv_mutex_t close_mutex;
uv_mutex_t free_mutex;
bool close_called;
bool free_called;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change the name to nanomsg_poll_ctx and refer to it throughout the code as struct nanomsg_poll_ctx.

}

// this function is called asynchronously after uv_close function call
void close_cb(uv_handle_t *handle) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static void close_cb(uv_handle_t *handle) {

@nickdesaulniers
Copy link
Owner

prefer #169

thank you for your help and interest in fixing this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants