欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

精简jre

程序员文章站 2022-05-25 23:18:28
...

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 jre精简