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

Residual JVM After Quitting #390

Closed
drguildo opened this issue Oct 20, 2013 · 26 comments
Closed

Residual JVM After Quitting #390

drguildo opened this issue Oct 20, 2013 · 26 comments

Comments

@drguildo
Copy link

Whenever I quit emacs or run nrepl-quit I get an orphaned JVM process remaining.

Attached should be an image showing the emacs process tree after running nrepl-jack-in.

I also tested with CIDER 20131018.1553 from a fresh .emacs.d with just cider/clojure-mode and had the same problem.

nrepl-jvm-bug

@drguildo
Copy link
Author

This Stack Overflow comment seems to indicate that the bug has been around since at least April.

@bbatsov
Copy link
Member

bbatsov commented Oct 20, 2013

I'll investigate the problem. Might be something Windows related, though - since I don't think I've seen orphaned processes on OSX and Linux.

@bbatsov
Copy link
Member

bbatsov commented Oct 30, 2013

This has to be something Windows specific, since I cannot reproduce it on OSX.

@drguildo
Copy link
Author

I'd be happy to help you debug the problem if you don't have a Windows install handy.

@drguildo
Copy link
Author

drguildo commented Nov 1, 2013

It's probably worth noting that I don't get this problem with any other programs that spawn a copy of the JVM. For example Leiningen spawns the same process structure but both java.exe processes are terminated when it exits.

@bbatsov
Copy link
Member

bbatsov commented Nov 25, 2013

You should debug what happens in cider--close-buffer when it's passed the connection buffer. You might instrument that function with C-u C-M-x and just invoke cider-quit. delete-process should normally kill the underlying Java process, but for some reason it seems that this is not happening on Windows.

@drguildo
Copy link
Author

I'm not familiar enough with nrepl.el/CIDER or elisp to know what I should be looking for.

It seems the parent java.exe process is getting killed, just not the child for some reason.

@bbatsov
Copy link
Member

bbatsov commented Nov 27, 2013

@drguildo Might be an Emacs bug then, since delete-process is a core Emacs function. You may get more info regarding this if you post a question on the emacs-devel mailing list.

@drguildo
Copy link
Author

I filed an Emacs bug and this is what one of the developers had to say:

Emacs on Windows can only monitor and kill its immediate subprocesses, it cannot monitor, let alone kill, any of their descendant processes, because it has no idea about them. And the OS doesn't automatically kill all the processes in the subprocess tree, and there's no way to send a signal to them all, as on Posix platforms. If killing the immediate child process doesn't cause some of its children to exit or abort, then those grandchildren will be left orphaned.

Why doesn't the child java.exe exit when it parent does? Can you arrange for that to happen? Failing that, I don't think there's a solution to this problem, sorry.

@bbatsov
Copy link
Member

bbatsov commented Nov 28, 2013

So I was correct when I assumed this was an Windows-related "bug". Since I don't use Windows, I don't know what we can do at this point. I guess we need some explicit tracking of processes there, but someone else will have to implement it.

@drguildo
Copy link
Author

If I run (System/exit 0) in the REPL, all Java processes are killed. Would it be possible to do this or something similar in cider--close-buffer?

@bbatsov
Copy link
Member

bbatsov commented Dec 4, 2013

I guess we can. I wonder if there are even simpler solutions to this problem.

@noisesmith
Copy link

IMHO assuming that the OS will kill a child process if we exit is not simple, it is sloppy. My vote is for explicitly shutting down any owned VM on shutdown of the host, and considering anything created via jack-in as owned.

@bbatsov
Copy link
Member

bbatsov commented Dec 19, 2013

@noisesmith Perhaps you're right. On the other hand I don't recall ever seeing someone tracking explicitly child processed in Emacs Lisp code. I'll look into that.

@drguildo A friend of mine (who's a crazy Windows hacker) checked that claim on emacs-devel and created a patch that debunks it - see the patch he provided here.

@JonyEpsilon
Copy link

I don't really have any expertise here, but let me add links to a couple of issues I've seen that might be relevant. There's a similar problem with orphaned JVMs in Gorilla REPL on Windows:

JonyEpsilon/lein-gorilla#4

@jtcb investigated a bit, and has good reason to suspect it's a leiningen problem:

technomancy/leiningen#1614

@bbatsov
Copy link
Member

bbatsov commented Jul 4, 2015

Closing this as there's not much we can do about it.

@mattiasw2
Copy link

I do not really understand why this issue was closed. It is a big problem, and it is not solved in Emacs 24.5 for Windows.

I currently use this workaround in .emacs

(defun my-kill-java ()
  (interactive)
  (cider-interactive-eval "(System/exit 0)")
  )

(defun turn-on-my-clojure-commands ()
   :
    (define-key clojure-mode-map (kbd "C-c q") 'my-kill-java)

  )

(add-hook 'clojure-mode-hook 'turn-on-my-clojure-commands)

@bbatsov
Copy link
Member

bbatsov commented Jan 3, 2016

It's closed because it's not a cider issue, it's an Emacs (or lein) issue.

@mattiasw2
Copy link

Ok, but maybe we should at least tell users about a workaround? The hanging java-processes will kill the machine, and a generic command like "pskill java" will also kill databases like datomic and cassandra.

How do I set the command for the repl too, i.e. what is the clojure-repl-mode-map called?

@bbatsov
Copy link
Member

bbatsov commented Jan 3, 2016

Ok, but maybe we should at least tell users about a workaround? The hanging java-processes will kill the machine, and a generic command like "pskill java" will also kill databases like datomic and cassandra.

I'd normally just inspect all Java processes and kill the relevant ones. As repl restarts are uncommon I don't think this is major issue anyways.

How do I set the command for the repl too, i.e. what is the clojure-repl-mode-map called?

cider-repl-mode-map.

@jconti
Copy link

jconti commented Mar 3, 2017

I think doing (shutdown-agents) lets the jvm quit by itself on windows. I think it is the windows JVM that starts some non-server thread that then blocks the normal exit. I wish I could recall what project I read this information in (maybe Nightcode, maybe ring-jetty, not sure).

@mattiasw2
Copy link

mattiasw2 commented Mar 4, 2017

I have solved it by calling (System/exit 0) from within the repl.

I added a command to .emacs

(defun my-kill-java ()
  (interactive)
  (cider-interactive-eval "(System/exit 0)")
  )
 (define-key cider-repl-mode-map (kbd "C-c C-q") 'my-kill-java)

If I just call (shutdown-agents) , pskill still finds two java-processes to kill. This doesn't happen when I use (System/exit 0)

benedekfazekas pushed a commit to benedekfazekas/cider that referenced this issue Jul 16, 2017
after quitting the REPL. Use `interrupt-process` instead of `kill-process` if OS
is windows.
benedekfazekas pushed a commit to benedekfazekas/cider that referenced this issue Jul 16, 2017
after quitting the REPL. Use `interrupt-process` instead of `kill-process` if OS
is windows.
benedekfazekas pushed a commit to benedekfazekas/cider that referenced this issue Jul 17, 2017
after quitting the REPL. Use `interrupt-process` instead of `kill-process` if OS
is windows.
bbatsov pushed a commit that referenced this issue Jul 17, 2017
#2051)

After quitting the REPL child Java processes on Windows weren't properly killed (likely an Emacs bug). Seems that `interrupt-process` does the trick, so now we use `interrupt-process` instead of `kill-process` if the OS is Windows.
@jconti
Copy link

jconti commented Jul 25, 2017

I've fussed with the code a bit. The solutions above using cider-interactive-eval block and sometimes leave orphaned cider interaction buffers. The following code has made my repl shutdown nicely reliable:

(defun my-kill-java ()
  (interactive)
  (cider-nrepl-send-unhandled-request
   (list "op" "eval"
         "code" "(do 
                   (.start 
                     (Thread. 
                       (fn [] 
                         (Thread/sleep 5000)
                         (shutdown-agents)
                         (System/exit 0)))) 
                  nil)"))
  (cider-quit 'QUIT-ALL))

@bbatsov
Copy link
Member

bbatsov commented Jul 26, 2017

Supposedly @benedekfazekas fixed this recently with benedekfazekas@7cd9c70

@jconti
Copy link

jconti commented Jul 27, 2017

I saw that, but did not think to test it. I will test and confirm. Thank you!

@jconti
Copy link

jconti commented Jul 28, 2017

The fix looks good to me. All the cases that used to leave a vm running, now do not.

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

No branches or pull requests

6 participants