java运行包精简探索(二)

前言

  • 框架选型结束还算顺利,接下来才是重头戏:jre运行环境的精简
  • 一个完整的jre环境动辄上百M,对于微型设备来说还是太大了


    jre8-win 199M
openjdk-jre-8-aarch64 102M

plan A ejdk

oracle官方有一个针对嵌入式设备的ejdk,可以通过自带的工具 jrecreate.sh 生成3个级别的jre,size 从10几M到30几M之间

燃鹅!!!哪怕是最大的30几M的包,运行我们的demo的时候也提示缺少包.......
而且由于arm板子上工具缺失,也不方便分析,所以 plan A 暂时搁置。

plan B 基于jdk8 进行精简

  • 通过大量的百度调研,发现jdk8的jre精简几乎都是一个思路:
    1、rt.jar的精简
    通过运行时添加 -verbose:class 来记录所有加载的class,然后分析其中来自rt.java的class,重新组装成一个rt.jar,用于替换jre里面的rt.jar

2、lib下的dll/so的精简
参考:https://blog.csdn.net/xiaoping8411/article/details/6973887
基于这个思路,自行编写了一个脚本文件:thin.sh

#!--bash

rm -rf tmp
mkdir tmp
mkdir tmp/jar
mkdir tmp/rt
mkdir tmp/third
mkdir tmp/ort
let thirdnum=0
let rtnum=0
let num=0

hasrt="n"

unzip -d tmp/jar -q $1
cat class.txt |egrep 'Loaded.*from' >tmp/loadedclass.txt
cat tmp/loadedclass.txt |sed  's/\[//g' |sed 's/!\/\]//g'  |sed 's/\]//g' |egrep '\.jar$' >>tmp/loaded.txt
total=`cat  tmp/loaded.txt |wc -l`
i=0
while read line
do
#echo "$i:$line"
l=($line)
#echo "${l[1]} ${l[3]}"
file="${l[1]}"
jar="${l[3]}"
file="${file//\.//}.class"
len="${#jar}"
#echo $len
let len=len-7
#echo $len
#echo $file
end="${jar:len}"
let num++

#echo $end
if [ "$end" = "/rt.jar" ] ;then
rtfile=$jar
echo "$num/$total*************get $file from rt.jar****************"  >>tmp/run.log
if [ "$hasrt" = "n" ] ;then
hasrt="y";
echo "init origin rt $rtfile"
fi
unzip -qo $rtfile  $file -d tmp/rt

let rtnum++

else
#jarfile="tmp/jar/${jar#jar:*jar!/}"
#unzip -q $jarfile  $file -d tmp/jar/BOOT-INF/classes/
let thirdnum++
#echo "$num/$total============get $file from third==============" >> tmp/run.log
#echo "$num/$total============get $file from $jarfile==============" 

fi


i=$((1+$i))
#if [ $i -eq 10000 ];
#then
# break;
#fi

done < tmp/loaded.txt 

echo "done rt class:$rtnum   third class :$thirdnum" 
echo "done rt class:$rtnum   third class :$thirdnum"  >>tmp/run.log


echo "zip............"
# cd tmp/third
#zip -r -q ../third.jar ./*
#cd tmp
#rm -rf jar/BOOT-INF/lib/*
#cp third.jar jar/BOOT-INF/lib/
#cd jar
#zip -r -q ../../slim-$1 ./*
#cd ..


#rm -rf /root/jre/jdk2/lib/rt.jar
cd tmp/rt
zip -r -q ../../rt.jar ./*
cd ../..

echo "===========done============="

  • 执行 /root/jre/jdk1/bin/java -jar -verbose:class solondemo.jar >>class.txt
  • 然后访问所有接口(后续考虑通过测试案例,代码覆盖率100%来保证load所有class)
    生成的rt.jar 替换掉jre的rt.jar 然后用替换后的jar来执行
    生成的rt.jar 5M左右。
    在windows环境可以正常运行。
  • 但是,在arm64环境下 使用OpenJDK8U-jre_aarch64_linux_hotspot_8u302b08做同样的操作,最终却得到一个异常


    error.png

而且连具体的异常是什么的偶不知道,突然就僵住了。

plan C 使用jdk11的模块化特性进行jre剪裁

  • 在solon群里分享了这一情况,群里有热心网友提到 性jdk9可以通过模块化对jre进行剪裁。


    热心网友在线支招.png
  • 简直是柳暗花明又一村,果断进行百度调研~~~~

由于jdk9并不是一个lts版本,17又有一些序列化的兼容性问题,所以最终决定用open jdk11进行尝试
https://jdk.java.net/archive/

openjdk11.png

  • 一开始打算把项目使用jdk11来编译,于是修改项目jdk版本,并添加module.java
2.jpg
1.jpg

4.jpg
(3.png

但是编译始终不通过。最后发现是在 .idea的目录下compiler.xml还有一个 bytecodeTargetLevel的配置需要修改


5

当然,群主也给了一个方案,就是删掉所有idea相关的信息,重新maven导入。

  • 编译通过,但是运行报错,大意是类没有export,于是在moudle描述中添加exports 但是又报出更多的权限问题
Unable to make field org.noear.weed.DbContext com.elitect.controller.DemoController.db1 accessible: module solondemo does not "opens com.elitect.controller" to module solon
权限问题.png

突然意识到,框架以及框架引用的其他第三方包 都是不支持模块化的,这样强行用是不行的。


java9 权限.png
  • java9+版本不再是publlic就可以被任何人的调用的时代了。(这个模块化的方案一定借鉴了karaf,又想起了被karaf支配的恐惧)

  • 于是改变思路,既然代码模块化暂不可行,那我还是用jdk8来对代码进行编译打包,只是用jdk11运行,应该可行吧,向下兼容应该还是有的吧。

  • 先把项目改回jdk8 并打包 solondemo.jar
    使用jdk11run一下:


    jdk11 run.png

    OK 没问题。

  • 使用jlink 打一个基础的jre(只包含 java.base模块)

./bin/jlink.exe  --module-path jmods --add-modules java.base --output ejre

生成的jre 40M
run一下试试:


base.png

虽然报错了,但是只是缺少包的错误,感觉有门啊。

  • 创建一个jdk11的空项目,main函数里面执行
System.out.println(org.xml.sax.InputSource.class.getModule());

得到结果

module java.xml

把java.xml模块也打进去

./bin/jlink.exe  --module-path jmods --add-modules java.base,java.xml --output ejre

再次运行
......
......
......
通过多次尝试,最终

./bin/jlink.exe  --module-path jmods --add-modules java.base,java.xml,java.naming,java.management,java.desktop,java.sql --output ejre

打出的包能完美运行我的demo了

  • 但是,jresize达到了60多M,有点超出预期了
  • 分析之前的过程发现一个问题,java.desktop是个什么鬼???为啥我一个web项目会用到java.desktop?
  • 而且desktop这个模块 有12M之大
  • 翻找之前的执行过程,发现是这里使用了java.beans.IntrospectionException这个类,这个类在desktop里


    desktop.png

群主帮忙分析后得出结论:是读取yaml的插件引用了这个类。
解决方案:不适用yaml配置,改为properties文件配置,并在pom里面 排除掉这个模块的引用solon.extend.properties.yaml

......
<dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-api</artifactId>
            <exclusions>
                <exclusion>
                <groupId>org.noear</groupId>
                <artifactId>solon.extend.properties.yaml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
......
 <dependency>
            <groupId>org.noear</groupId>
            <artifactId>weed3-solon-plugin</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.noear</groupId>
                    <artifactId>solon.extend.properties.yaml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

完美!!!!跑起来了,功能也正常(同时 项目jar再次减小0.3M)


撒花.png

最终可使用的jre生成配置:

./bin/jlink.exe  --module-path jmods --add-modules java.base,java.xml,java.naming,java.management,java.sql --output ejre

生成的ejre目录总共52M


52M jre.png
//TODO arm环境测试 MACOS 测试 linux 测试
//TODO 又有群友提了一下 graalvm 据说springboot项目,编译之后的可执行代码就30-40MB 值得一试!plan D 又来了,真是计划赶不上变化!
鸣谢:noear (https://gitee.com/noear)
大補丁 (热心群友)
Joat(热心群友)
初见是惊鸿一瞥 (热心群友)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268