jvm - 如何在没有运行缺点的Windows上获取Java进程的线程和堆转储

我有一个Java应用程序,我从控制台运行,然后控制台执行另一个Java进程。 我想获得该子进程的线程/堆转储。

在Unix上,我可以做一个kill -3 ,但在Windows AFAIK上获取线程转储的唯一方法是在控制台中使用Ctrl-Break。 但这只会让我转移父进程,而不是孩子。

有没有另一种方法来获得堆转储?

15个解决方案

342 votes

假设您知道pid,则可以使用pid获取正在运行的任何进程的转储。

使用任务管理器或资源监视器来获取pid.然后

jmap -dump:format=b,file=cheap.bin

获取该进程的堆。

rkaganda answered 2019-03-05T15:42:37Z

104 votes

您混淆了两个不同的Java转储。 jmap生成线程转储,而不是堆转储。

线程转储=将JVM输出中的每个线程的堆栈跟踪作为文本输出到stdout。

堆转储= JVM进程输出到二进制文件的内存内容。

要在Windows上进行线程转储,如果JVM是前台进程,则CTRL + BREAK是最简单的方法。 如果你在Windows上有类似unix的shell,如Cygwin或MobaXterm,你可以像在Unix中一样使用jmap。

要在Unix中进行线程转储,如果JVM是前台进程,则使用CTRL + C,或者只要为JVM获得正确的PID,就可以使用jmap。

无论使用哪种平台,Java都有几个可以提供帮助的实用程序。 对于线程转储,jmap是您最好的选择。[http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstack.html]

只是为了完成转储问题:堆转储不常用,因为它们很难解释。 但是,如果你知道在哪里/如何看待它们,它们中有很多有用的信息。 最常见的用法是查找内存泄漏。 最好在java命令行上设置jmap,以便在OutOfMemoryError,-XX:+HeapDumpOnOutOfMemoryError上自动生成堆转储但是,您也可以手动触发堆转储。 最常见的方法是使用java实用程序jmap。

注意:此实用程序并非在所有平台上都可用。 自JDK 1.6起,jmap可在Windows上使用。

示例命令行看起来像

jmap -dump:file=myheap.bin {pid of the JVM}

输出“myheap.bin”不是人类可读的(对于我们大多数人来说),你需要一个工具来分析它。 我的偏好是MAT。[http://www.eclipse.org/mat/]

Derek answered 2019-03-05T15:44:13Z

27 votes

我认为在Linux进程中创建.hprof文件的最佳方法是使用jmap命令。 例如:jmap -dump:format=b,file=filename.hprof {PID}

Roberto Flores answered 2019-03-05T15:44:40Z

17 votes

除了使用上面提到的jconsole / visualvm之外,您还可以在另一个命令行窗口中使用jstack,并捕获该输出。

< vm-id> 可以使用任务管理器(它是Windows和unix上的进程ID)或使用jstack找到。

jstack和jps都包含在Sun JDK版本6及更高版本中。

ankon answered 2019-03-05T15:45:21Z

16 votes

我推荐使用JDK(jvisualvm.exe)分发的Java VisualVM。 它可以动态连接并访问线程和堆。 我发现一些问题非常宝贵。

Lawrence Dol answered 2019-03-05T15:45:48Z

14 votes

请尝试以下选项之一。

对于32位JVM:

jmap

对于64位JVM(明确引用):

jmap

对于VM参数中具有G1GC算法的64位JVM(仅使用G1GC算法生成活动对象堆):

jmap

相关的SE问题:使用jmap命令的Java堆转储错误:过早的EOF

在本文中查看jmap的各种选项

Ravindra babu answered 2019-03-05T15:47:03Z

11 votes

如果你想在内存不足的情况下使用heapdump,可以使用选项-XX:-HeapDumpOnOutOfMemoryError启动Java

C.F. JVM选项参考页面

Daniel Winterstein answered 2019-03-05T15:47:39Z

11 votes

如果你在服务器jre 8及以上,你可以使用这个:

jcmd PID GC.heap_dump /tmp/dump

Atul Soman answered 2019-03-05T15:48:07Z

6 votes

您可以运行jconsole(包含在Java 6的SDK中),然后连接到您的Java应用程序。 它将向您显示每个Thread运行及其堆栈跟踪。

Steve Kuo answered 2019-03-05T15:48:36Z

5 votes

您可以从Cygwin发送kill -3 。 您必须使用Cygwin ps选项来查找窗口进程,然后将信号发送到该进程。

krosenvold answered 2019-03-05T15:49:09Z

4 votes

您必须将第二个java可执行文件的输出重定向到某个文件。然后,使用SendSignal向您的第二个进程发送“-3”。

Yoni Roit answered 2019-03-05T15:49:38Z

3 votes

如果您使用的是JDK 1.6或更高版本,则可以使用jmap -dump:format=b,file=sample_heap_dump.hprof 1234命令来获取Java进程的堆转储,条件是您应该知道ProcessID。

如果您使用的是Windows计算机,则可以使用任务管理器获取PID。 对于Linux机器,您可以使用各种命令,如jmap -dump:format=b,file=sample_heap_dump.hprof 1234或netstat -tupln | grep java或top | grep java,具体取决于您的应用程序。

然后你可以使用像jmap -dump:format=b,file=sample_heap_dump.hprof 1234这样的命令,其中1234是PID。

有多种工具可用于解释hprof文件。 我将推荐Oracle的visualvm工具,它易于使用。

Badal answered 2019-03-05T15:50:34Z

2 votes

我为Java 8(使用View the message和View the message)编写了一个名为View the message的小批处理脚本,它转储了线程,堆,系统属性和JVM args。

:: set the paths for your environment

set PsExec=C:\Apps\SysInternals\PsExec.exe

set JAVA_HOME=C:\Apps\Java\jdk1.8.0_121

set DUMP_DIR=C:\temp

@echo off

set PID=%1

if "%PID%"=="" (

echo usage: jvmdump.bat {pid}

exit /b

)

for /f "tokens=2,3,4 delims=/ " %%f in ('date /t') do set timestamp_d=%%h%%g%%f

for /f "tokens=1,2 delims=: " %%f in ('time /t') do set timestamp_t=%%f%%g

set timestamp=%timestamp_d%%timestamp_t%

echo datetime is: %timestamp%

echo ### Version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo ### Uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo ### Command >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.command_line >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo ### Flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

echo ### Properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.system_properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% Thread.print -l >"%DUMP_DIR%\%PID%-%timestamp%-threads.log"

%PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% GC.heap_dump "%DUMP_DIR%\%PID%-%timestamp%-heap.hprof"

echo Dumped to %DUMP_DIR%

它必须在启动JVM的用户的同一Windows会话中运行,因此如果通过远程桌面连接,则可能需要在View the message中启动命令提示符并从那里运行它。 例如

%PsExec% -s -h -d -i 0 cmd.exe

这将在交互式会话中提示您(单击底部的任务栏图标)到View the message,这将转到另一个会话中的新控制台,您可以从该控制台运行jvmdump.bat脚本。

isapir answered 2019-03-05T15:51:25Z

0 votes

如果由于某种原因你不能(或不想)使用控制台/终端,还有另一种解决方案。 您可以让Java应用程序为您打印线程转储。 收集堆栈跟踪的代码非常简单,可以附加到按钮或Web界面。

private static String getThreadDump() {

Map allStackTraces = Thread.getAllStackTraces();

StringBuilder out = new StringBuilder();

for (Map.Entry entry : allStackTraces.entrySet()) {

Thread thread = entry.getKey();

StackTraceElement[] elements = entry.getValue();

out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));

out.append('\n');

for (StackTraceElement element : elements) {

out.append(element.toString()).append('\n');

}

out.append('\n');

}

return out.toString();

}

此方法将返回如下所示的字符串:

main | prio=5 | RUNNABLE

java.lang.Thread.dumpThreads(Native Method)

java.lang.Thread.getAllStackTraces(Thread.java:1607)

Main.getThreadDump(Main.java:8)

Main.main(Main.java:36)

Monitor Ctrl-Break | prio=5 | RUNNABLE

java.net.PlainSocketImpl.initProto(Native Method)

java.net.PlainSocketImpl.(PlainSocketImpl.java:45)

java.net.Socket.setImpl(Socket.java:503)

java.net.Socket.(Socket.java:424)

java.net.Socket.(Socket.java:211)

com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:59)

Finalizer | prio=8 | WAITING

java.lang.Object.wait(Native Method)

java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)

java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)

java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

Reference Handler | prio=10 | WAITING

java.lang.Object.wait(Native Method)

java.lang.Object.wait(Object.java:502)

java.lang.ref.Reference.tryHandlePending(Reference.java:191)

java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

对于那些对带有流的Java 8版本感兴趣的人来说,代码更加紧凑:

private static String getThreadDump() {

Map allStackTraces = Thread.getAllStackTraces();

StringBuilder out = new StringBuilder();

allStackTraces.forEach((thread, elements) -> {

out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));

out.append('\n');

Arrays.stream(elements).forEach(element -> out.append(element.toString()).append('\n'));

out.append('\n');

});

return out.toString();

}

您可以使用以下方法轻松测试此代码

System.out.print(getThreadDump());

HugoTeixeira answered 2019-03-05T15:52:18Z

-1 votes

在Oracle JDK上,我们有一个名为jmap的命令(可在Java Home的bin文件夹中找到)。该命令的用法如下

jmap(选项)(pid)

示例:jmap -dump:live,format = b,file = heap.bin(pid)

Suresh Ram answered 2019-03-05T15:53:04Z

java 线程不足_jvm - 如何在没有运行缺点的Windows上获取Java进程的线程和堆转储...相关推荐

  1. scala java funtion1_当我在ScalaIDE中运行代码时,为什么要获取`java.lang.NoClassDefFoundError:scala / Function1`?...

    这是一个简单的测试,我用来从 Java调用Scala方法: public static void main(String args[]) { java.util.Map> rec = news. ...

  2. Windows上的Java线程CPU分析

    本文将为您提供一个教程,介绍如何在Windows OS上快速查明Java线程贡献者与CPU严重问题有关. Windows与Linux,Solaris和AIX等其他操作系统一样,使您可以在进程级别监视C ...

  3. java 中window_教你如何在windows上安装Java

    最近够倒霉的,电脑硬盘坏了,重新做了个系统,各种环境全都没了,/(ㄒoㄒ)/~~ 然后我发现自己在重新安装各种环境的时候,有些东西竟然还需要去查,所以决定把这些环境的配置都写成博客记录下来. 今天就教 ...

  4. 推动Windows的限制:进程和线程

    这是我推行Windows系列的第四篇文章,探讨Windows基础资源的界限.这一次,我将讨论Windows上支持的最大线程数和进程数限制.我将简要介绍一下线程和进程之间的区别,调查线程限制,然后调查进 ...

  5. 如何在Windows上下载java

    如何在Windows上下载java 第一步.在官网下载安装包 首先,进入JAVA官方网址 https://www.oracle.com/java/technologies/javase-downloa ...

  6. 你如何在java中获取线程堆_如何在Windows上获取未在控制台中运行的Java进程的线程和堆转储...

    问题 我有一个Java应用程序,我从控制台运行,然后控制台执行另一个Java进程.我想获得该子进程的线程/堆转储. 在Unix上,我可以做akill -3 但是在Windows AFAIK上获取线程转 ...

  7. 零基础如何在windows上进行JAVA开发

    文章目录 前言 一.JDK安装 1.什么是JRE和JDK 2.下载JDK 2. 配置环境变量 二.下载和使用 intellij idea 1.进入官网下载 2.配置 intellij idea 3.代 ...

  8. mscoreei.dll没有被指定在windows上运行_在Windows上使用Docker运行.NetCore

    今天我们来说下如何在windows下使用docker运行.net core,既然是docker,那么我们首先得在windows上安装docker. 在Windows安装 docker 有两种选择 : ...

  9. 将java项目导出jar包,然后转成在windows上的可执行文件(没有java运行环境的电脑也可以)

    近期在做一个java串口项目,需要将完整的项目导出.exe文件在没有java环境的电脑上运行,下面是详细的操作步骤以及遇到各种问题的解决办法.. 1.将项目导出jar包,使用的工具是eclipse,该 ...

最新文章

  1. WinForm应用只运行一次
  2. Qt OpenGL裁剪测试
  3. Kaggle Kernels和 Colab, Binder, Azure Notebooks, CoCalc, Datalore的比较
  4. 58技术主席:还原万亿级三高业务场景的设计与实践
  5. 国庆快乐,送3本Python书
  6. Zookeeper本地安装配置(windows)
  7. ActiveMQ学习(四)——应用程序接口
  8. 微信小程序项目源代码SSM校园生活小助手+后台
  9. Linux Shall命令入门
  10. 算法题15 穿越沙漠问题,飞机加油问题
  11. 南京大学计算机系统实验报告,南京大学 计算机系统基础 课程实验 2018(PA3)
  12. CH340安卓驱动使用教程
  13. MQTT Qos详解(一)
  14. druid源码学习2-DruidDataSource.DestroyTask
  15. 知识众筹第9期 一个经典案例学会数据分析 | 开始分红报名
  16. (个人学习笔记)利用ensight进行EDEM耦合FLUENT后处理
  17. 【Google Play】创建和管理内部测试版本 ( 创建内部测试版本 | 检查并发布内部测试版本 )
  18. grafana可视化
  19. QT QPaintEvent update repaint 高帧率画图
  20. 互联网摸鱼日报(2022-11-10)

热门文章

  1. 粤嵌GE6818实现识别触摸坐标的识别
  2. 【剑指offer】Java版代码(完整版)
  3. MVC的Controller-Action布局:单独的创建/编辑页面还是创建/编辑/查看一体的页面?...
  4. 简单干净的C#方法设计案例:SFCUI.AjaxValue()之三
  5. IT职场人生系列之十九:危险职业(中)
  6. 爬虫 正则 bs4 xpath 中文乱码 管道符
  7. P1533 可怜的狗狗
  8. 一个介绍傅立叶变换的好文章
  9. 幸福就是有人爱、有事做、有所期待(转)
  10. 基于Callable和Future的匹配文件数量计算实例