精简JRE的思路初探

引言: JRE是Java程序赖以运行的基础环境,目前JRE已经非常的庞大;即使为了运行一个简单的Hello World的程序,可能依然需要依赖整个JRE,将近百兆大小的依赖性。是否可以对特定Java程序依赖的JRE进行精简呢? 当然是可以,根据当前代码的需要,动态精简JRE,只依赖需要的class,而非全部。

1.  整体的思路

  a.  首先找到当前Java程序依赖的所有class,包括自身类库/第三方类库,以及JRE中的类库。

  b.   将JRE中不需要的类库文件移除掉,只保留需要的类库。

  C.   将保留下的类库重新打包,替换已有的JRE文件

2.  寻找所需的JRE中的类库文件

  在运行Java应用的过程中,可以针对JVM添加参数[-XX:+TraceClassLoading],则应用在启动过程中,会将所有的所需的class打印到控制台。  

 在上述的例子中,就列出所有依赖的类库。

2. 如何提取需要的类库或者移除不需要的类库

 这里我们采用前者,只提取所需的类库。

jar xvf xxx.jar classname1 classname2 ....
  这个命令就会把需要的class从jar中提取出来,复制到本地当前目录。

3.  将这些类库进行打包,替换掉JRE中对应的类库

jar cvf target.jar sourcefolder1 classfolder2 ...
   打包命令,将classfolder中的类库,打包为target.jar.

4. 那代码上如何,利用上述的只是完成自动化打包 JRE对应的类库呢?

方案如下:

4.1. 基于运行过程中的Java参数-XX:+TraceClassLoading,打印出所用在JRE中用到的java类

4.2. 捕获从控制台输出的class列表

4.3. 利用jar自带的功能,从rt.jar中提取相应的所需要的class

4.4. 将rt.jar中提取的class进行打包,即可得到所需的jre核心jar包。

代码假定的前提:

    1. Jre所在的路径

    2. 目标java类已经编译成class.这里未考虑动态编译的情况

   3.  将jre中的rt.jar打包在当前路径。

      示例代码如下:

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.List;

public class RunClass {

	public static void main(String[] args) throws IOException {
		List<String> classes = new ArrayList<String>();

		String[] cmdB = { "java", "-XX:+TraceClassLoading", "MainTest" };
		Runtime runtime = Runtime.getRuntime();

		Process process = Runtime.getRuntime().exec(cmdB);
		// /process = Runtime.getRuntime().exec(cmdB);
		LineNumberReader br = new LineNumberReader(new InputStreamReader(
				process.getInputStream()));
		StringBuffer sb = new StringBuffer();
		String line;
		while ((line = br.readLine()) != null) {
			String className = RunClass.parseClass(line);
			if (className.length() > 0) {

				sb.append(className.replace(".", "/")).append(" ");
				classes.add(className.replace(".", "/"));
			}
		}

		System.out.println("classes to be packed in size:" + classes.size());

		classes.add(0, "/opt/jdk7/jre/lib/rt.jar");
		classes.add(0, "xvf");
		classes.add(0, "jar");

		Process jarClass = runtime.exec((String[]) classes
				.toArray(new String[classes.size()]));
		LineNumberReader br1 = new LineNumberReader(new InputStreamReader(
				jarClass.getInputStream()));
		StringBuffer sb1 = new StringBuffer();
		String line1;
		while ((line1 = br.readLine()) != null) {
			System.out.println("extracting:" + line1);
		}
		System.out.println(classes.size()
				+ " classes have been extracted successfully");

		String[] cmdJarPackage = { "jar", "cvf", "rt.jar", "com", "java",
				"javax", "META-INF", "org", "sun", "sunw" };
		Process jarProcess = runtime.exec(cmdJarPackage);

		System.out
				.println("Jar the classes into a package rt.jar successfully.");

	}

	public static String parseClass(String lineStr) {
		String keyStr = "";

		if (lineStr.startsWith("[Loaded")) {
			String[] keys = lineStr.split(" ");

			if (keys.length == 4) {
				keyStr = keys[1];
			}
		}

		return keyStr;
	}

}

5. 总结

 JRE在jDK8中已经对其进行了模块化设计,从而使按需加载和定制JRE成为可能。这里的示例代码只是简单示意了流程,离真正的工具化还有较大差距;主要的原因是大量使用了Runtime.exec方法来直接调用命令,这样不是很灵活和可控;比如打包和解压可以利用JarOuputStream, JarInputStream等来进行等,会更加可控和灵活。

   

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
精简jre步骤 1. 拷贝一个完整版的jre文件夹到D盘 2. 删除jre目录下所有出bin和lib目录的所有文件或目录 3. 打开cmd窗口,设置path路径为空,转到D:\jre\bin目录,运行java –version。正常显示当前Java的版本。 4. 在bin目录中新建一个temp目录,将除java.exe和java.dll外的移到temp目录中 5. 再次运行java –version命令,提示没找到verify.dll。将temp目录中的verify.dll移到bin目录中 6. 再次运行 java –version命令,提示:Could not create the Java virtual machine.错误 7. 根据测试:还要将hpi.dll和zip.dll放到bin目录中 8. 再次运行java –version命令,OK,又出现了版本信息。此时,可以将temp目录移出bin目录中。(放到桌面先) 9. 删除client目录中的除jvm.dll外的文件。转到jre目录,查看bin目录的大小,为2.89MB。但此时lib目录仍有60M有余 10. 转到lib目录,新建一个temp目录,将i386除外的目录都移动到temp目录中,再次运行java –version命令,OK 11. 再新建一个temp2目录,将charsets.jar和rt.jar外的所有文件移动到temp2目录中,再次运行 Java –version命令,OK 12. 将temp2和temp目录移到桌面。此时lib仍有48.7M接近50M。(还得努力) 13. 缩减charsets.jar和rt.jar(使用7z工具可以查看和修改jar文件的内容『直接添加和删除』)。准备做个软件来实现。 14. 缩减原则。运行java -verbose:class -version > temp.java 命令,此时在bin目录下生成了一个temp.java文件,用EditPlus打开,看到没有,要加载的就是那些类了,把不需要的全部删除就是了。 15. 原来charsets.jar没有加载呀。直接删除,再次运行java –version命令,OK 16. 接下来的工作就是裁剪rt.jar了。慢慢来。也可以做个软件来完成。可以下载一个GreenJVMMake.jar来完成。不过有时候好像有些类没加载到。要考虑更新了。 17. 裁剪玩rt.jar后,再次运行java –version ,出现了版本信息。OK 18. 转到D盘查看一下精简jre才4.47MB。不到5M。OK 19. 最小的jre制作完毕。 附带制作过程图片,可用Picasa来查看,播放模式效果更佳。 Thoams 2010-6-25 15:53

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值