写一个正确的状态机有多难
作者:互联网
最近给JDK修了一个存在3年的bug。故事的起因是这样的,我们的一个测试在Windows下会莫名其妙地卡住,但是如果稍微把项目文件夹改个名字,增加或者减少一个字符(比如说从gradle
改成gradle1
或者gradl
),这个测试就如丝般顺滑。
俗话说,能重现的bug都是好bug。一番调试之后,发现问题似乎出在JDK本身。
故事要从Argument File说起,这玩意的中文名是啥我也不知道,就不翻译了。大家都知道,Java世界里的一切最终都会变成java
命令行的调用。在Windows上,大概长这样:
java -Xmx2g -cp "C:\1.jar;C:\2.jar" Main doSomething
如果你有一个很大的应用,引用了成百上千个jar包,那么你的classpath可能会特别长,长到几十K都装不下。然而,Windows万分悲痛地告诉你,不好意思,我的命令行长度是有限制的,不能超过8191个字符。
你:……
以前,大家对此的解决方案一般是,创建一个空jar包,然后把这个巨型的classpath写到manifest文件里,然后引用这个空jar包即可:https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html 。Bazel就是这么干的。
JDK 9之后,官方给了一个解决方案:Argument Files。
简而言之,你不是有个巨型无敌长的classpath么?不用直接传到命令行里了,先把这个巨型的参数-cp "C:\1.jar;C:\2.jar;...;C:\10000.jar"
写到一个文件里,比如说叫classpath.txt,然后直接用java @classpath.txt ...
就行了,java
命令会自动帮你展开。要注意的是,不仅是classpath,任何被java
接受的参数都可以用这种方式传递。
坏就坏在Argument File的处理上。我一步一步研究上面遇到的那个诡异bug,最终找到了一个可以复现的样例。在特定情况下,Argument File的读取会出现问题。比如说,如果你有一个Argument File,内容是:
-cp ".;C:\app.jar" Main
我们假定Main类存在于app.jar中,因此一切正常。接下来,我们逐渐向双引号中增加.;
:
-cp ".;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;.;C:\app.jar" Main
你会发现,当这个文件增长到一定长度(大约4100字节)时候,突然,java告诉你:
大专栏
标签:java,正确,jar,classpath,Argument,状态机,多难,cp,bug 来源: https://www.cnblogs.com/liuzhongrong/p/12371560.html