Skip to content

memory leak / retention #899

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

Closed
nilbus opened this issue Feb 17, 2023 · 3 comments · Fixed by #918
Closed

memory leak / retention #899

nilbus opened this issue Feb 17, 2023 · 3 comments · Fixed by #918
Labels
bug Something isn't working

Comments

@nilbus
Copy link

nilbus commented Feb 17, 2023

Your environment

  • ruby -v: ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
  • rdbg -v: rdbg 1.7.1

Describe the bug
After shipping a Rails app with the debug gem bundled and required via debug/open_nonstop, memory usage grew with each request.

memory usage before and steadily growing after bundling debug

Expected behavior
Memory is not retained during the request cycle


Our goal is to have the Rails process ready for a debugger process to attach in staging environments.

Do you have an idea of what memory might be allocated and retained across requests? Can this be worked around?

@jaynetics
Copy link

jaynetics commented Feb 21, 2023

i can confirm this is a problem.

i compared multiple memory dumps over time as described here and found these leaks:

Retained 49881 ARRAY objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/thread_client.rb:111
Retained 49867 HASH objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/thread_client.rb:119
Retained 49858 OBJECT objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/session.rb:1488
Retained 49853 HASH objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/thread_client.rb:113
Retained 49849 DATA objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/session.rb:1488
Retained 49840 HASH objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/thread_client.rb:114
Retained 49835 DATA objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/thread_client.rb:112
Retained 49809 ARRAY objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/session.rb:1488
Retained 33265 IMEMO objects at: /app/vendor/bundle/ruby/3.1.0/gems/mini_magick-4.11.0/lib/mini_magick/shell.rb:45
Retained 33259 ARRAY objects at: /app/vendor/ruby-3.1.2/lib/ruby/3.1.0/open3.rb:223
Retained 33251 ARRAY objects at: /app/vendor/bundle/ruby/3.1.0/gems/mini_magick-4.11.0/lib/mini_magick/shell.rb:45
Retained 33241 DATA objects at: /app/vendor/bundle/ruby/3.1.0/gems/mini_magick-4.11.0/lib/mini_magick/shell.rb:46
Retained 33231 ARRAY objects at: /app/vendor/bundle/ruby/3.1.0/gems/mini_magick-4.11.0/lib/mini_magick/shell.rb:46
Retained 33229 DATA objects at: /app/vendor/bundle/ruby/3.1.0/gems/mini_magick-4.11.0/lib/mini_magick/shell.rb:45
Retained 16650 DATA objects at: /app/vendor/ruby-3.1.2/lib/ruby/3.1.0/open3.rb:223
Retained 16641 ARRAY objects at: /app/vendor/bundle/ruby/3.1.0/gems/mini_magick-4.11.0/lib/mini_magick/tool.rb:111
Retained 16634 FILE objects at: /app/vendor/ruby-3.1.2/lib/ruby/3.1.0/open3.rb:97
Retained 16633 FILE objects at: /app/vendor/ruby-3.1.2/lib/ruby/3.1.0/open3.rb:93
Retained 16628 OBJECT objects at: /app/vendor/bundle/ruby/3.1.0/gems/mini_magick-4.11.0/lib/mini_magick/tool.rb:91

there is some symmetry of the debug object numbers with the mini_magick + open3 numbers, so maybe there is a memory leak in some gems, such as mini_magick (see also minimagick/minimagick#544) and that leak is greatly exacerbated by the debug gem? or debug itself is leaky.

either way, debug should probably include big warnings so people don't load it in production...

edit: i didn't require 'debug/open_nonstop' like OP. having gem 'debug' in the Gemfile was sufficient to cause the problem.

@ko1
Copy link
Collaborator

ko1 commented Mar 7, 2023

Thank you for the information.

Retained 49809 ARRAY objects at: /app/vendor/bundle/ruby/3.1.0/gems/debug-1.6.1/lib/debug/session.rb:1488
-> added at thread creation. it should be free'ed when the thread is free'ed

And maybe all of them are based on same reason.

Maybe your program making many threads. I'll think about it.

@ko1 ko1 added the bug Something isn't working label Mar 7, 2023
@ko1 ko1 added this to the v1.8.0 milestone Mar 7, 2023
ko1 added a commit that referenced this issue Mar 7, 2023
@ko1 ko1 closed this as completed in #918 Mar 8, 2023
ko1 added a commit that referenced this issue Mar 8, 2023
@nilbus
Copy link
Author

nilbus commented Mar 8, 2023

Nice discovery! I'll try to confirm this fix later today or sometime this week.

st0012 added a commit to Shopify/debug that referenced this issue Mar 30, 2023
* DAP: use Object#__send__ to avoid name conflicts

* DAP: allow custom request extension in Session class

* Fix bug that "trace line" does not work after stopping trace once

* Increase timeout in debug_code

* Fix warning about unused variable

* Avoid memberless Struct

Related to Ruby bug 19416.

* Remove redundant raw detach test

The test's subject is the `disconnect` request with `restart: false,
terminateDebuggee: <true|false>` arguments, which has been covered by the
tests in `disconnect_dap_test.rb`. So this test case has become obsolete.

Co-authored-by: Andy Waite <[email protected]>

* Always propagate keyword arguments in WebSocketServer

* Fix `::Process::daemon` patch

As discussed here:
ruby@699a31e#r94469355

* Add test

* Use local variables

* Add test for info consts with an expression

Co-authored-by: Andy Waite <[email protected]>

* Fix typo in README

* ⬆️ Update ci ruby versions

* ⏪ Revert Ruby 2.6

* ✏️ Fix typo

* CDP: Support evaluating expression on non-current frame

* CDP: support reattaching in Chrome DevTools

Close ruby#800

* Improved stability for chrome debugging

- Display the greeting message regardless of the status of invocation of
  chrome.

  This allows coming back to the debugger on a new tab when the window
  process by `UI_CDP.run_new_chrome` is killed.

- Handle `Errno::ESRCH` in `UI_CDP.cleanup_reader`.

  When the process by `UI_CDP.run_new_chrome` is killed, re-killing it
  breaks your debugging session and in turn the "debugee".

* Make `UI_ServerBase#puts` to behave like `STDERR#puts`

`UI_ServerBase#greeting` calls `#puts` with no arguments, this
breaks reconnections to the debugger.

* Handle not existing $FILENAME in `Session#process_protocol_request`

`Session#process_protocol_request` gracefully handles `Errno::ENOENT`
when `eval`-ing `$FILENAME`, and it doens't exist.

* free terminated ThreadClients

fix ruby#899

* DAP: use Mutex when sending response

When debug.gem tries to send response from multiple threads, the socket connection is closed. I confirmed this bug when using custom request from vscode-rdbg

* Make sure to fail when remote debuggee does not exit after scenarios

Because Errno::EPIPE is rescued while sending message to socket, protocol_test_case_test.rb does not pass. protocol_test_case_test.rb had been passed because ReaderThreadError was occurred and the debuggee process was still alive. Here is a scenario. After closing socket, terminated event was sent. However socket was closed, so debuggee process raised Errno::EPIPE and debugggee process was still alive. The test framework detected the status and failed.

Thus I fixed so that the test framework does not kill the debuggee process unexpectedly.

* Alias Session send methods in WebSocketServer 

Methods ``respond``, ``respond_fail`` and ``fire_event`` can be aliased to ``send_response``, ``send_fail_response`` and ``send_event``, respectively.

* Fix timing bug on session_server creation

`@session_server` should be assigned at first.

`@session_server = Thread.current` in the session thread does not
work because the creator thread can access to `@session_server`
before it.

* Fix useless assignments

  Found by running `rubocop --only=Lint/UselessAssignment`

* Remove Tracer#puts as it's not used

* Avoid raising debuggee not finished error if assertions failed

When assertions failed, we should let the AssertionFailedError surface
and not calling flunk so we can get correct failure messages.

* Fix test builder

* DAP: allow custom request extension in ThreadClient class

* DAP: introduce Rdbg Record Inspector

* Revert "DAP: introduce Rdbg Record Inspector"

This reverts commit e29faba.

* relax authority check

to pass on the Windows.
fix ruby/vscode-rdbg#169

* Add test for global variable support in DAP and CDP

* Add test for instance variable ordering in DAP

PR ruby#806 sorts instance variables by name before returning them. This
commit adds a test that verifies this functionality under the DAP
protocol.

* Fix incorrect method name

* dap/cdp_result -> protocol_result

From ThreadClient it retunrs :dap_result or :cdp_result to the SESSION.
This patch renames it to `:protocol_result` and it will be handled
by `process_protocol_result`.

* separate 'test_console' and 'test_test'

* `test_all` should also run `test_test`

* Omit slow tests for healty CI

* add workflow

* DAP: rename the method name of custom request

Follow up for ruby#939

Change the name from "request_..." to "custom_dap_request_" in UI_DAP and ThreadClient for consistency

* DAP: support custom request in session class

UI_DAP -> Session: custom_dap_request_...

Session -> ThreadClient: custom_dap_request_event_...

Add "request_event" prefix to clarify it is a response (not Events in DAP)

* Add test for DAP's command execution through evaluate request

* Enqueue DAP's evaluate command right away

* DAP: echo back the given command

on `, debug_command` form.

* remain breakpoints on reloaded files

Breakpoints should be remained on reloaded files. To make sure
maintaining loaded file names.

fix ruby#870

* Use better approach to signal remote process' exit status

1. `remote_info.failed_process` stores symbol but we only use the value's
   presence to check if the process is force-killed.
2. The force-killed status is directly controlled by `kill_safely` through
    `kill_remote_debuggee`, which is directly called right before we check
    the status with `remote_info.failed_process`.

Combining the two, we can just let `kill_safely` and `kill_remote_debuggee` to
return the force-killed status and not storing it in `remote_info`, which
already contains a bunch of information.

This also eliminates the need to pass `test_info` to `kill_safely`, which
makes related code easier to understand and maintain.

* Remove unused failed_process attribute

* Add "result" as an argument to custom_dap_request_event method

The generated result in ThreadClient is passed as "result". We usually use it when returning responses to VS Code in Session class

* restart all threads on eval

When a thread keeps a lock, and REPL runs a code which needs the
lock, other threads should make a progress to release the lock.

fix ruby#877

* CDP: support remote debugging in different environment

From investigation by @ko1-san, the path to set breakpoints seems to be sent in "url" field when debugging in different environment such as WSL(running debuggee) and Windows(running Chrome DevTools). I supported "url" field in this PR.

* `-v` prints version and do something

Without this patch, `rdbg -v target.rb` prints version and terminates
the process. With this pach, `-v` prints version and starts debugging
for `target.rb`.

If no filename is given, terminates the process.

* v1.7.2

* Revert "Workaround VS Code's breakpoint skipping issue"

This reverts commit 4313d91.

* Revert "Avoid locking all threads on debugger suspension"

This reverts commit 1e0f45c.

* Revert "Always insert preset commands when executing commands from DAP (#4)"

This reverts commit 8eea4c9.

---------

Co-authored-by: Naoto Ono <[email protected]>
Co-authored-by: Takashi Kokubun <[email protected]>
Co-authored-by: Andy Waite <[email protected]>
Co-authored-by: Jeremy Evans <[email protected]>
Co-authored-by: Andy Waite <[email protected]>
Co-authored-by: Mau Magnaguagno <[email protected]>
Co-authored-by: Vinicius Stock <[email protected]>
Co-authored-by: yamashush <[email protected]>
Co-authored-by: Jose D. Gomez R <[email protected]>
Co-authored-by: Koichi Sasada <[email protected]>
Co-authored-by: Emily Samp <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants