`

精简jre

    博客分类:
  • java
阅读更多

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

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics