精简jre
0. 思路:
1)把自己的应用程序打包成可运行的jar包
2)通过jar命令运行这个jar包
3)把jar包所需要的类全部打印到文本文件中
4)把上一步产生的类从文件中提取出来重新打包
5)去掉jre中bin和lib目中下的不需要的文件和目录
1. 打包运行,使用下面bat将所用到的类全部输出到文件中
@echo off set path=.\jre\bin .\jre\bin\java -jar -verbose:class lottery.jar > class.txt @pause
2. class.txt文件处理
class.txt文件格式如下
[Opened D:\baiduyundownload\Lottery\jre\lib\rt.jar] [Loaded java.lang.Object from D:\baiduyundownload\Lottery\jre\lib\rt.jar] [Loaded java.io.Serializable from D:\baiduyundownload\Lottery\jre\lib\rt.jar] [Loaded java.lang.Comparable from D:\baiduyundownload\Lottery\jre\lib\rt.jar] [Loaded java.lang.CharSequence from D:\baiduyundownload\Lottery\jre\lib\rt.jar] [Loaded java.lang.String from D:\baiduyundownload\Lottery\jre\lib\rt.jar]
这里使用到的是rt.jar和charsets.jar,将其分别抽取出来,抽取出来的格式如下:
sun/nio/cs/ext/ExtendedCharsets sun/nio/cs/ext/GBK sun/nio/cs/ext/DoubleByteDecoder sun/nio/cs/ext/GBK$Decoder sun/nio/cs/ext/DoubleByteEncoder sun/nio/cs/ext/GBK$Encoder
抽取步骤:
grep rt.jar class.txt > rt.txt # 32位的jvm,使用rt.jar有下面这种格式 grep "from shared objects file" class.txt >> rt.txt grep charsets class.txt > charsets.txt vi命令 %s/\[Loaded //g # 替换掉行头 %s/ from *.*//g # 替换掉行尾 %s/\./\//g # .替换成/
3. 重新打包
1)首先将jre目录中的rt.jar, charsets.jar分别解压到输入目录,运行如下代码
参数:./data/rt.txt ./data/rt ./output/rt
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; public class ReduceClasses { /** * 文件拷贝 * * @param srcFileName * @param destFileName * @return */ public static boolean copy(String srcFileName, String destFileName) { try { FileInputStream in = new FileInputStream(new File(srcFileName)); FileOutputStream out = new FileOutputStream(new File(destFileName)); try { byte[] bytes = new byte[1024]; int c = -1; while ((c = in.read(bytes)) != -1) out.write(bytes, 0, c); in.close(); out.close(); } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } catch (Exception e) { e.printStackTrace(); return (false); } return (true); } /** * 读取路径,copy * * @param classFile * @param srcRtDir * @param destRtDir * @return * @throws IOException */ public static int dealClass(String classFile, String srcRtDir, String destRtDir) { int sucessCount = 0; try { LineNumberReader reader = new LineNumberReader(new FileReader(new File(classFile))); try { String line = null; while ((line = reader.readLine()) != null) { int pos = line.lastIndexOf("/"); if (pos > 0) { File dir = new File(destRtDir + line.substring(0, pos)); if (!dir.exists()) dir.mkdirs(); String srcFileName = srcRtDir + line + ".class"; String destFileName = destRtDir + line + ".class"; if (copy(srcFileName, destFileName)) sucessCount++; else { System.out.println(line); } } } } finally { if (reader != null) { reader.close(); } } } catch (IOException e) { e.printStackTrace(); } return sucessCount; } public static void main(String[] args) { if (args == null || args.length != 3) { System.err.println("Usage: ReduceClasses classFile srcRtDir destRtDir"); } String classFile = args[0]; // 运行JAR生成的,应用程序所需类的txt文件 String srcRtDir = args[1]; // rt.jar解压后的目录 String destRtDir = args[2]; // 抽取的类存放目录 if (!srcRtDir.endsWith("/")) { srcRtDir += "/"; } if (!destRtDir.endsWith("/")) { destRtDir += "/"; } System.out.print("Success Count: " + dealClass(classFile, srcRtDir, destRtDir)); } }
2)将原有rt目录中的META-INF拷贝到新的rt目录中去,进入新的rt目录,使用rar打成zip包,然后重命名为rt.jar. charsets同样处理
4. 精简jre中其他无用文件
1)新建jre目录,在其中建两个子目录bin和lib
2)将新生成的rt.jar和charsets.jar拷贝到lib中
3)从原生jre的lib中拷贝出i386和zi两个子目录,其中zi里面只保留America和Asia两个目录
4)原生jre的lib中除了库文件和文件夹之外的所有属性文件都要拷贝到新的lib中
5)在运行jar包时查看该进程使用到的dll,将这些dll保存到新的bin目录中去
5. 查看运行进程所用使用到的dll
tasklist /m >dll.txt &&dll.txt
java.exe 6376 ntdll.dll, kernel32.dll, KERNELBASE.dll,
ADVAPI32.dll, msvcrt.dll, sechost.dll,
RPCRT4.dll, jvm.dll, USER32.dll, GDI32.dll,
LPK.dll, USP10.dll, WINMM.dll, IMM32.DLL,
MSCTF.dll, verify.dll, java.dll, PSAPI.DLL,
zip.dll, swt-win32-3659.dll, ole32.dll,
OLEAUT32.dll, comdlg32.dll, SHLWAPI.dll,
COMCTL32.dll, SHELL32.dll, WININET.dll,
urlmon.dll, CRYPT32.dll, MSASN1.dll,
iertutil.dll, uxtheme.dll,
QvodExtend_x64.dll, VERSION.dll,
WS2_32.dll, NSI.dll, dwmapi.dll,
CRYPTBASE.dll, CLBCatQ.DLL
6. 结果:
我的jre中:
bin |
---
client |
--- jvm.dll
java.dll
java.exe
verify.dll
zip.dll
精简完的jre是4M多
7. 参考文章
http://yaojialing.iteye.com/blog/1067409
上一篇: java map的重复键值的排序
下一篇: C#简单实现防止多个程序运行的方法