eclipse 本地工程单元测试出现can not run program"XXXX/javaw.exe" error=87

报这个错有2个解决方法:

1. 修改长路径:http://www.myexception.cn/ruby-rails/439356.html

当eclipse控制台报出Cannot run program “"C:\Program Files\Java\jre6\bin\javaw.exe" (in directory "D:\workspace\test"): CreateProcess error=87, 2êy′í”的错误时,可以考虑是不是因为eclipse里设置的某个环境变量路径(可通过Window->Preferences->Java->Build Path->Classpath Variables查看)太长太深。我遇到的问题是因M2_REPO这个环境变量引起的,它存储的是maven本地库的位置。

解决方法:

一、

1、在较浅的目录新建maven本地库文件夹。例如D:/m2。
2、修改%MAVEN_HOME%/conf/settings.xml文件,修改<localRepository></localRepository>节点的内容为<localRepository>D:/m2</localRepository>。
(注:默认<localRepository></localRepository>节点是被注释掉的,本地库路径指向C:\Documents and Settings\CURRENT_USER\.m2\repository,其中CURRENT_USER为当前登录用户名。这种情况下,只需要在文件中添加<localRepository>D:/m2</localRepository>即可。)
3、将原maven本地库中的所有包拷贝到新目录D:/m2中。
4、修改eclipse中M2_REPO环境变量的值(Window->Preferences->Java->Build Path->Classpath Variables),把原M2_REPO值修改为D:/m2。
5、F5刷新工程,如果工程前还带红叉,可以执行Project->Clean...。over~

二、 如果还不成功,按照这个方法

http://blog.youkuaiyun.com/vking_wang/article/details/9168057

谷歌说是因为classpath太长的缘故,WINDOW官网上讲:the max command prompt line length in windows xp is 8191 characters。

解决办法当然是让classpath变短,可以删掉哪些不用的path。

如果每个path都是有用的,该怎么办呢?

可以尝试:

eclipse --> Run --> Run configuration --> 在classpath tab页中找到default classpath,右击 --> Edit --> 选中Only include exported entries

---------------------------------------------------------------------可耻的分割线--------------------------------------------------------------------------------------------

(最开始发现这个问题,是在自己运行单元测试的时候发现的就是报这个error=87的错,开始觉得自己不怎么写单元测试,就没管它,就这样困扰了我大概2周左右的时间,今天准备写下单元测试,发现这个问题绕不过去了,花了我2个多小时的时间解决了这个问题。就是用的解决方法一)

以后遇到这样的问题,要及时解决,以免夜长梦多~~~~~~~~~

eclipse.buildId=unknown java.version=1.8.0_232 java.vendor=Azul Systems, Inc. BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US Command-line arguments: -os win32 -ws win32 -arch x86 -clean !ENTRY org.eclipse.platform 2 0 2025-09-01 10:38:17.140 !MESSAGE Could not resolve module: org.eclipse.platform [204] Unresolved requirement: Require-Bundle: org.eclipse.ui.intro; bundle-version="[3.2.0,4.0.0)" !ENTRY org.eclipse.osgi 4 0 2025-09-01 10:38:17.140 !MESSAGE Application error !STACK 1 java.lang.NullPointerException at com.ami.veb.ui.VeBApplication.checkInstanceLocation(VeBApplication.java:499) at com.ami.veb.ui.VeBApplication.start(VeBApplication.java:278) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:380) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:235) 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:498) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:648) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:603) at org.eclipse.equinox.launcher.Main.run(Main.java:1465)
最新发布
09-02
!SESSION 2025-08-11 13:41:01.459 ----------------------------------------------- eclipse.buildId=unknown java.version=1.8.0_172 java.vendor=Oracle Corporation BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US Command-line arguments: -os win32 -ws win32 -arch x86 -clean !ENTRY org.eclipse.platform 2 0 2025-08-11 13:41:02.540 !MESSAGE Could not resolve module: org.eclipse.platform [204] Unresolved requirement: Require-Bundle: org.eclipse.ui.intro; bundle-version="[3.2.0,4.0.0)" !ENTRY org.eclipse.osgi 4 0 2025-08-11 13:41:02.540 !MESSAGE Application error !STACK 1 java.lang.NullPointerException at com.ami.veb.ui.VeBApplication.checkInstanceLocation(VeBApplication.java:493) at com.ami.veb.ui.VeBApplication.start(VeBApplication.java:280) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:380) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:235) 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:498) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:648) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:603) at org.eclipse.equinox.launcher.Main.run(Main.java:1465)
08-12
<think>我们正在分析用户提供的JVM参数配置,并解释为什么Eden区在达到26MB时就触发了垃圾回收(GC)。用户提供的参数如下: ``` java -vm ./jre/bin/javaw.exe -Dfile.encoding=UTF-8 -vmargs -Xms1024m -Xmx1024m -Xmn512m -XX:SurvivorRatio=2 -XX:MaxTenuringThreshold=5 --add-exports=java.base/jdk.internal.access=ALL-UNNAMED -Dfile.encoding=UTF-8 ``` ### 步骤1:解析JVM参数 首先,我们解析这些参数的含义: - `-Xms1024m`:初始堆大小为1024MB。 - `-Xmx1024m`:最大堆大小为1024MB。 - `-Xmn512m`:年轻代(Young Generation)大小为512MB。 - `-XX:SurvivorRatio=2`:设置Eden区与一个Survivor区的比例。具体来说,`SurvivorRatio=2`表示Eden区与一个Survivor区的比例是2:1。注意,年轻代中包括一个Eden区和两个Survivor区(From Survivor和To Survivor)。 - `-XX:MaxTenuringThreshold=5`:对象在年轻代中经历的最大GC次数(即年龄阈值),超过这个次数后对象会被晋升到老年代。 - `-Dfile.encoding=UTF-8`:设置文件编码为UTF-8(这里出现了两次,但效果相同,以最后一个为准)。 ### 步骤2:计算年轻代各区域大小 根据参数`-Xmn512m`(年轻代总大小)和`-XX:SurvivorRatio=2`,我们可以计算Eden区和每个Survivor区的大小。 - `SurvivorRatio=2`的含义:Eden区大小与一个Survivor区大小的比值为2:1。 - 年轻代(Young Generation)由1个Eden区和2个Survivor区组成,因此: - 总年轻代大小 = Eden区大小 + 2个Survivor区大小 - 设Survivor区大小为S,则Eden区大小为2S。 - 因此:2S + 2S = 4S = 512MB (注意:这里2S(Eden)+ 2S(两个Survivor)?不对,应该是2S(Eden)+ S + S = 4S?不对,重新计算:Eden=2S, 两个Survivor各为S,所以总大小为2S + S + S = 4S?不对,因为两个Survivor是相等的,所以总大小= Eden + 2 * Survivor = 2S + 2 * S? 不对,应该是2S(Eden) + S(第一个Survivor) + S(第二个Survivor)= 4S?不对,这样就是4S=512MB,那么S=128MB,Eden=2*128=256MB。 但是,实际上,`-XX:SurvivorRatio`的官方解释是:Eden区与一个Survivor区的大小比例。因此,如果`SurvivorRatio`的值为2,则Eden区大小是一个Survivor区大小的2倍。所以,年轻代总大小 = Eden + 2 * Survivor = 2S + 2 * S = 4S? 不对,应该是:Eden = 2S, 每个Survivor = S,所以总大小 = 2S + S + S = 4S。 因此: - 4S = 512MB - S = 128MB - Eden区大小 = 2 * 128 = 256MB - 每个Survivor区大小 = 128MB ### 步骤3:分析Eden区分配 根据上述计算,Eden区大小为256MB。那么为什么在Eden区只使用了26MB时就触发了GC呢? 可能的原因: 1. **分配担保失败(Allocation Failure)**:当年轻代无法为新对象分配空间时,会触发Minor GC。但是,Eden区有256MB,而只使用了26MB,显然还有大量空间,所以不太可能是因为Eden区满了。 2. **主动触发GC**:程序中可能调用了`System.gc()`,但用户没有提到程序中有主动调用。 3. **大对象直接进入老年代**:如果创建的对象很大(比如超过Eden区剩余空间,或者超过某个阈值),那么对象可能会直接进入老年代。但是,26MB相对于256MB来说并不大,所以不太可能因为大对象而触发GC。 4. **元空间(Metaspace)不足**:如果元空间满了,会触发Full GC,但这里我们讨论的是Eden区,所以不太相关。 5. **其他原因**:比如程序刚启动时,初始对象分配导致Eden区被使用,但26MB后触发GC,可能是由于JVM自身的机制。 ### 步骤4:考虑JVM的垃圾回收机制 实际上,JVM在启动后,会根据其内部算法动态调整堆的使用情况。但是,在用户配置中,我们没有看到显式指定垃圾收集器,所以默认情况下,在JDK1.8中,使用的是Parallel Scavenge(新生代)+ Parallel Old(老年代)。 此外,还有一个重要的参数:`-XX:MaxTenuringThreshold=5`,它影响对象晋升到老年代的年龄阈值。 ### 步骤5:考虑JVM的初始化和自适应调整 JVM在启动初期,会进行一些初始的内存分配和调整。但更关键的是,我们注意到用户设置中,堆的初始大小和最大大小相同(都是1024MB),年轻代固定为512MB(通过`-Xmn512m`设置)。这意味着JVM不会动态调整年轻代的大小。 但是,为什么Eden区在26MB就触发GC呢?一个可能的原因是:**在程序启动初期,对象分配的速度很快,虽然Eden区有256MB,但是JVM在启动时可能只分配了一小部分内存(按需分配),然后当分配达到某个阈值时,触发了第一次GC**。然而,这个解释并不准确,因为JVM通常会在启动时分配整个年轻代(包括Eden和Survivor)的物理内存(取决于操作系统和JVM实现)。 ### 步骤6:检查日志中的GC原因 要准确分析,需要查看GC日志。我们可以通过添加GC日志参数来获取详细信息: ``` -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log ``` 但是,用户没有提供日志,所以我们只能推测。 ### 步骤7:考虑分配速率和GC策略 另一个可能的原因是:**分配速率过高,导致Eden区快速填充**。但是,用户提到只达到26MB,这相对于256MB来说很小。 ### 步骤8:考虑TLAB(Thread Local Allocation Buffer) 每个线程在Eden区中会有一块私有的分配缓冲区(TLAB)。当TLAB用尽时,需要申请新的TLAB,如果Eden区剩余空间不足以分配新的TLAB,则可能触发GC。但是,26MB的分配不太可能导致整个Eden区无法分配新的TLAB(因为TLAB通常很小,默认大小与线程数有关,但一般不会超过几百KB)。 ### 步骤9:检查参数配置是否有误 我们注意到用户提供的参数中,有两个`-Dfile.encoding=UTF-8`,一个在`-vmargs`之前,一个在之后。但是,根据Java命令行参数解析规则,`-vmargs`之后的参数是传递给JVM的,之前的参数可能是传递给启动器(如javaw)的。所以,实际上JVM接收到的参数是`-vmargs`后面的那些,即: ``` -Dfile.encoding=UTF-8 -Xms1024m -Xmx1024m -Xmn512m -XX:SurvivorRatio=2 -XX:MaxTenuringThreshold=5 --add-exports=java.base/jdk.internal.access=ALL-UNNAMED ``` 但是,第一个`-Dfile.encoding=UTF-8`可能被启动器忽略,因为启动器参数通常不是JVM参数。所以,最终JVM参数是后面的那些。 ### 步骤10:考虑Survivor区空间不足 在Minor GC发生时,会尝试将Eden区和From Survivor区中存活的对象复制到To Survivor区。如果To Survivor区空间不足以容纳这些存活对象,则会通过分配担保机制提前将对象转移到老年代。但是,这通常发生在GC过程中,而不是在分配过程中直接触发GC。 ### 可能的原因:自适应调整的阈值 实际上,JVM的垃圾回收触发条件并不是固定达到Eden区的100%才触发。在Parallel Scavenge收集器中,有一个参数`-XX:MaxGCPauseMillis`(默认是200ms),收集器会尝试调整堆的大小(但这里堆大小是固定的)和晋升年龄等来达到这个目标。但是,在固定堆大小的情况下,收集器可能会根据历史数据预测回收时间,从而在Eden区使用率较低时就触发GC,以避免一次回收时间过长。 但是,在第一次GC之前,收集器没有历史数据,所以这个解释也不充分。 ### 另一个可能的原因:预热阶段 JVM在启动初期,会有一个初始化的过程,可能会创建一些对象然后快速丢弃,然后触发第一次GC。但是,26MB的分配量对于启动过程来说并不算小。 ### 关键点:Eden区26MB触发GC的合理解释 我们注意到,用户观察到的现象是Eden区达到26MB时触发GC。根据我们的计算,Eden区大小为256MB,26MB大约是10%。那么,为什么会在10%的时候触发GC呢? 实际上,Parallel Scavenge收集器有一个特性:它使用一个自适应策略来控制GC的触发时机。具体来说,它通过一个称为“Eden区占用比例”的阈值来决定是否触发GC。这个阈值在初始时可能设置得比较低,然后随着运行逐渐调整。 在Parallel Scavenge收集器中,有一个参数`-XX:InitialSurvivorRatio`(默认是8),但更相关的是GC的自适应调整策略。然而,在固定年轻代大小的情况下,第一次GC的触发时机可能是由JVM内部的一个初始阈值决定的。 ### 结论 最可能的原因是:**在JVM启动后的初始阶段,由于没有历史数据,垃圾收集器采用了一个保守的触发阈值(比如10%),以避免在第一次GC时停顿时间过长。随着运行,这个阈值会动态调整。** 因此,当Eden区分配达到26MB(约256MB的10%)时,触发了第一次Minor GC。在后续的运行中,这个触发阈值会逐渐调整到接近100%,即Eden区快满的时候才触发GC。 ### 验证方法 为了验证,可以添加GC日志参数,观察后续的GC触发时机。如果后续的GC触发时Eden区使用率接近100%,则说明是自适应调整的结果。 ### 建议 如果用户希望减少初始阶段的GC次数,可以考虑以下方法: 1. 关闭自适应调整:使用`-XX:-UseAdaptiveSizePolicy`,但这样收集器会使用固定规则(通常是在Eden区满时触发)。 2. 调整初始阈值:但Parallel Scavenge收集器没有直接设置初始阈值的参数。 不过,通常这种初始阶段的GC对性能影响不大,可以忽略。 ### 相关问题 根据以上分析,生成相关问题: §§相关问题§§ 1. 如何通过GC日志分析Minor GC的触发原因? 2. Parallel Scavenge收集器的自适应调整策略有哪些? 3. 如何调整JVM参数以避免过早触发Minor GC? 4. 在固定堆大小下,如何优化垃圾回收性能? 5. 如何计算年轻代中Eden区和Survivor区的具体大小?</think>根据您提供的 JVM 参数配置,我们来分析 Eden 区在仅使用 26MB 时就触发垃圾回收的原因。以下是关键参数解析和原因分析: ### 关键参数解析 ```bash -Xms1024m -Xmx1024m # 堆固定为 1024MB -Xmn512m # 年轻代固定为 512MB -XX:SurvivorRatio=2 # Eden 与单个 Survivor 区比例 = 2:1 ``` ### 年轻代分区计算 根据 `SurvivorRatio=2`: - 年轻代 = Eden + Survivor1 + Survivor2 - 设 Survivor 区大小为 $S$ - 则 Eden = $2S$(比例 2:1) - 总年轻代:$2S + S + S = 4S = 512\text{MB}$ - 解得: $$S = 128\text{MB}$$ $$\text{Eden} = 2 \times 128 = 256\text{MB}$$ ### Eden 区 26MB 触发 GC 的原因 1. **TLAB 分配机制** JVM 为每个线程分配 **Thread Local Allocation Buffer (TLAB)**,默认大小约 256KB-1MB。当线程的 TLAB 用尽且 Eden 剩余空间**不足分配新 TLAB** 时,会触发 GC。26MB 可能恰逢多个线程同时耗尽 TLAB。 2. **年轻代空间担保失败** 当老年代**剩余空间 < 年轻代对象总大小**时(通过 `-XX:HandlePromotionFailure` 检测),即使 Eden 未满也会提前触发 GC。您配置中老年代仅 512MB(堆 1024MB - 年轻代 512MB),容易触发此机制。 3. **大对象直接分配** 若创建的对象大小 **> Eden 区 50%**(约 128MB),会直接进入老年代。但 26MB 对象不会触发此机制。 4. **元空间/metaspace 触发** 如果同时存在 **类加载操作**,元空间不足会触发 Full GC,连带回收年轻代(但您未配置元空间参数)。 ### 配置优化建议 ```diff - -Xms1024m -Xmx1024m + -Xms1024m -Xmx2048m # 扩大堆空间减少老年代压力 - -XX:SurvivorRatio=2 + -XX:SurvivorRatio=6 # 增大 Eden 占比 + -XX:MaxTenuringThreshold=15 # 提高晋升阈值 + -XX:NewRatio=3 # 年轻代占堆1/3(替代-Xmn) + -XX:MetaspaceSize=256m # 防止元空间触发GC ``` ### 验证方法 添加 GC 日志参数分析触发原因: ```bash -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log ``` 日志中关键字段解释: ``` Allocation Failure # Eden空间不足 Metadata GC Threshold # 元空间触发 System.gc() # 手动调用 ``` ### 根本原因推测 最可能是 **TLAB 分配失败** 或 **老年代空间担保失败**(`PromotionFailure`)导致,因为: 1. Eden 配置为 256MB,26MB 仅占 10% 2. 老年代空间紧张(仅 512MB) 3. 未配置 TLAB 优化参数 > 可通过 GC 日志中的 `[PSYoungGen: 26214K->192K(256000K)]` 字段确认 Eden 使用量[^1][^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值