[注意:我认为资源泄漏了(请参阅下面的答案),但我仍然很好奇为什么命令行蚂蚁确实终止但是in-java ant没有]
我在Java程序中调用了一个复杂的ant目标。它没有错误地运行。但最终程序不会终止。我通过maven execute从NetBeans调用该程序。
如果我从命令行调用ant目标,它会终止。如果我在程序结束时写System.exit(0);
,它就会终止。
所以,我假设我错过了一些对ant库的调用,告诉它关闭所有的流等,或者我的ant脚本中有资源泄漏。我认为它是资源泄漏,因为jstack
报告了一个开放流(见下文) - 我怎么能找到那里打开的?
以下是我对蚂蚁的致电:
public boolean callToAnt() {
File antFile = new File("C:\somepath\build.xml");
File logfile = new File("C:\somepath\antlog.log");
File projectBasePath = antFile.getParentFile();
try (PrintStream logfilestream = new PrintStream(new FileOutputStream(logfile))) {
Project project = new Project();
project.setUserProperty("ant.file", antFile.getAbsolutePath());
project.init();
ProjectHelper helper = ProjectHelper.getProjectHelper();
ProjectHelper.configureProject(project, antFile);
project.setBaseDir(projectBasePath);
project.addReference("ant.projectHelper", helper);
project.setProperty("foo", "bar"); // some properties
project.addBuildListener(getDefaultLogger(logfilestream));
project.executeTarget("myTarget");
return true;
} catch (Exception ex) {
Logger.getLogger(this.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}
}
我尝试拨打project.fireBuildFinished(null);
,但这并未改变任何内容。
如果我注释掉蚂蚁部分,程序就会终止。如果我离开记录器,它仍然不会终止。
我将离开蚂蚁脚本本身,因为它分布在许多文件上并且非常复杂。我的目标是学习如何自己找到资源泄漏,然后解决这个问题。
日志文件也不包含任何错误(以“BUILD SUCCESSFUL”结尾)。
我在进程停止时调用jstack
,这就是结果:
2015-03-23 09:51:40
Full thread dump Java HotSpot(TM) Client VM (25.25-b02 mixed mode):
"Thread-1" #10 daemon prio=5 os_prio=0 tid=0x15b14400 nid=0x120c waiting on condition [0x152ff000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at org.apache.commons.exec.InputStreamPumper.run(InputStreamPumper.java:69)
at java.lang.Thread.run(Thread.java:745)
"Thread-3" #12 daemon prio=5 os_prio=0 tid=0x15bb9000 nid=0x15b4 runnable [0x164af000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:224)
at org.apache.commons.exec.StreamPumper.run(StreamPumper.java:105)
at java.lang.Thread.run(Thread.java:745)
"Thread-2" #11 daemon prio=5 os_prio=0 tid=0x15bb4000 nid=0x10fc runnable [0x1506f000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:246)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
- locked <0x049b25b8> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at org.apache.commons.exec.StreamPumper.run(StreamPumper.java:105)
at java.lang.Thread.run(Thread.java:745)
"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x14cbb000 nid=0x17f4 runnable [0x00000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x14caa000 nid=0xcf4 waiting on condition [0x00000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x14ca9000 nid=0x16c8 waiting on condition [0x00000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x14ca6000 nid=0x13fc runnable [0x00000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0081f000 nid=0x1324 in Object.wait() [0x14ebf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x09bfc108> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:142)
- locked <0x09bfc108> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:158)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0081a000 nid=0xca0 in Object.wait() [0x14c1f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x09bfc2a8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)
- locked <0x09bfc2a8> (a java.lang.ref.Reference$Lock)
"main" #1 prio=5 os_prio=0 tid=0x000acc00 nid=0x12f4 runnable [0x0221e000]
java.lang.Thread.State: RUNNABLE
at java.lang.ProcessImpl.waitForInterruptibly(Native Method)
at java.lang.ProcessImpl.waitFor(ProcessImpl.java:449)
at org.apache.commons.exec.DefaultExecutor.executeInternal(DefaultExecutor.java:347)
at org.apache.commons.exec.DefaultExecutor.execute(DefaultExecutor.java:160)
at org.codehaus.mojo.exec.ExecMojo.executeCommandLine(ExecMojo.java:610)
at org.codehaus.mojo.exec.ExecMojo.execute(ExecMojo.java:352)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
"VM Thread" os_prio=2 tid=0x00815800 nid=0xa44 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x14cc4c00 nid=0x9b4 waiting on condition
JNI global references: 38
答案 0 :(得分:1)
我认为您必须使用分析器并附加到运行ant脚本。分析线程转储和/或跟踪对象分配。这应该立刻揭示任何泄漏,假设有一个泄漏。 JVisualVm随SDK一起提供,因此您可以使用它。我认为这是一个相当不错的探索者。
答案 1 :(得分:0)
使用调试器。它非常无聊,需要一些时间,但你会发现问题是什么。
你必须逐步调试任何被调用的类 - 很高兴ant,maven等都是开源的,所以你可以通过NetBeans下载源代码。 (打开项目中的依赖项,右键单击所有有趣的内容,然后选择“下载源代码&#39;”
然后你逐步完成你的程序,直到你发现某些东西被打开。 System.exit(0)
工作,但让程序运行的事实表明Object引用没有得到清理。在调试器运行时,您可以在调试视图中看到该工具的运行线程。如果最后还有任何遗漏,你必须找出他们开始的地方。
要执行该程序,直到其中一个弹出。记住代码和状态中的位置,根据需要创建断点,停止程序并重新启动 - 这一次在导致附加线程出现的行之前停止并进入该方法,重复。