• 转载 jre精简


    前不久给朋友做了一个桌面程序,程序文件没多大,但运行java程序需要jre,但jre足足有80M多,然后在网上搜了如何给给JRE瘦身或精简JRE,整理如下:

    打开JRE安装目录.目录包括bin,lib二个文件夹,所以就是将这两个文件进行瘦身了,

    1. bin: 可以认为这是Java虚拟机.

    2. lib: 执行class文件时,Java虚拟机需要用到的类库及资源文件.

    一、bin瘦身主要从两方面考虑

    ① exe文件,最主要的工具是java.exe,它用来执行class文件,如果只是为了单纯运行Java程序的话,其他可执行文件一般都是用不到的(可剔除). 

    ② DLL文件,是java.exe执行class文件过程中调用的,执行class文件,java.exe需要哪个库文件就加载哪个dll,不需用的可以剔除.

    我们要做的就是找到哪些DLL文件是有用?我们运行一个Java文件看看,可以利用360安全卫士得到

    1、准备java文件:

    [html] view plaincopy
     
    1. /*  
    2. @author jarg  
    3. @TODO 举例查看当前程序必需的dll文件  
    4. */  
    5. import java.io.InputStreamReader;  
    6. import java.io.IOException;  
    7.   
    8. public class Hello  
    9. {  
    10.     public static void main(String[] args) throws IOException  
    11.     {  
    12.         InputStreamReader ir = new InputStreamReader(System.in);  
    13.         System.out.println("Hello");  
    14.         ir.read();  
    15.     }  
    16. }  

    2、编译、运行

    3、360安全卫士 -> 功能大全 -> 进程管理器 右上角的显示加载到当前选中进程中的dll

    4、这样我们留下java.exe、有用的dll文件和client目录就行

    到这里bin的瘦身成功!

    二、lib的瘦身

    ① lib目录最主要的类库是rt.jar,是任意Java程序所必需的类库.
    lib目录大约62MB,但是rt.jar类库就占了47MB,可见精简bin目录,最主要是裁剪rt.jar.

    ② lib目录下一个运行Java程序不可或缺的文件是位于i386下的虚拟机配置文件jvm.cfg.该配置文件用来管理不同版本的jvm.dll.其内容作为java.exe,javac.exe的全局变量,用来加载相应的动态链接库文件.

    ③ lib目录里面除了包含程序运行所需要的类库及配置文件外,还包含有一些诸如: 鼠标光标,字体等系统资源.简单程序如果未用到这部分资源的话,可以剔除.如果程序除去JRE部分,占用空间较大的话,为了避除资源加载错误带来的麻烦,建议保留这不到20MB的配置文件内容.

    主要步骤如下:

    1、提取我们需要的类库(jar),借助-verbose命令,查看虚拟机在运行Java程序时所加载的所有类,如:

    [plain] view plaincopy
     
    1. @echo off  
    2. C:/Java/jdk1.6.0_16/bin/java -jar  -classpath lib/*.jar; -verbose:class printSoft.jar >> class.txt  
    3. pause  

    在class.txt文件中保存如下的信息:

    [plain] view plaincopy
     
    1. [Loaded java.lang.Math from shared objects file]  
    2. [Loaded java.nio.charset.Charset$3 from C:Javajdk1.6.0_16jrelib t.jar]  
    3. [Opened C:Javajdk1.6.0_16jrelibcharsets.jar]  
    4. [Loaded sun.nio.cs.AbstractCharsetProvider from C:Javajdk1.6.0_16jrelib t.jar]  
    5. [Loaded sun.nio.cs.ext.ExtendedCharsets from C:Javajdk1.6.0_16jrelibcharsets.jar]  
    6. [Loaded java.lang.Class$1 from shared objects file]  
    7. [Loaded sun.reflect.ReflectionFactory$1 from shared objects file]  
    8. [Loaded sun.reflect.NativeConstructorAccessorImpl from shared objects file]  

    我们可以从class.txt中得到我们需要的jar文件和class文件,提交jar很简单,我就不说了,下面我们在看看如何提交我们用到的class文件:

    由于class.txt每行都是形同: [Loaded java.lang.System from shared objects file]的一串字符,修改文本以方便获取类完整名java.lang.System,从而获得类似类路径java/lang/System的一串字符,方便后继编写类拷贝程序.
    修改方法:
    1. 查找并替换[Loaded 为空,达到删除[Loaded 的目的.
    2. 使用任意一个具有正则表达式查找替换功能的文本编辑器,查找并替换 from.*为空,达到删除 from及其后面的字符串的目的.
    3. 查找并替换.为/
    4. 删除以[Opened 开头的行.
    5. 删除程序中System.out.println的输出行.
    提取之后class.txt就剩下如下信息:

    [plain] view plaincopy
     
    1. java/lang/Object  
    2. java/io/Serializable  
    3. java/lang/Comparable  
    4. java/lang/CharSequence  
    5. java/lang/String  
    6. java/lang/reflect/GenericDeclaration  
    7. .......  

    2、从现有的jar包中提取我们整理的class文件,然后打包成jar,最终取代原有的jar,下面是一个提取class的工具类:

    [java] view plaincopy
     
    1. import java.io.BufferedReader;  
    2. import java.io.File;  
    3. import java.io.FileInputStream;  
    4. import java.io.FileOutputStream;  
    5. import java.io.IOException;  
    6. import java.io.InputStreamReader;  
    7.   
    8. public class CopyClass  
    9. {  
    10.     private String source = "C:\Users\lzp\Desktop\printSoft\jre6\lib\";      // 类源目录  
    11.     private String dest = "C:\Users\lzp\Desktop\printSoft\jre6\lib\";        // 类拷贝目的目录  
    12.     String[] jarArr = new String[]{"rt","charsets"};  
    13.     /*** 
    14.      *  
    15.      * @param source 类源目录 
    16.      * @param dest   类拷贝目的目录 
    17.      * @param jarArr 需要的提取的jar文件 
    18.      */  
    19.     public CopyClass(String source,String dest,String[] jarArr){  
    20.         this.source=source;  
    21.         this.dest=dest;  
    22.         this.jarArr=jarArr;  
    23.     }  
    24.   
    25.     public static void main(String[] args)  
    26.     {  
    27.         String[] jarArr = new String[]{"rt","charsets"};  
    28.         CopyClass obj = new CopyClass("C:\Users\lzp\Desktop\printSoft\jre6\lib\",  
    [java] view plaincopy
     
    1.                                                          "C:\Users\lzp\Desktop\printSoft\jre6\lib\",jarArr);  
    2.         obj.readAndCopy("C:\Users\lzp\Desktop\printSoft\class.txt");  
    3.     }  
    4.   
    5.     /*** 
    6.      * @param logName 提取class明细 
    7.      */  
    8.     public void readAndCopy(String logName)  
    9.     {  
    10.         int count = 0;  // 用于记录成功拷贝的类数  
    11.         try  
    12.         {  
    13.             FileInputStream fi = new FileInputStream(logName);  
    14.             InputStreamReader ir = new InputStreamReader(fi);  
    15.             BufferedReader br = new BufferedReader(ir);  
    16.   
    17.             String string = br.readLine();  
    18.             while(string != null)  
    19.             {  
    20.                 if(copyClass(string) == true)  
    21.                     count++;  
    22.                 else  
    23.                     System.out.println("ERROR " + count + ": " + string);  
    24.                 string = br.readLine();  
    25.             }  
    26.         }  
    27.         catch (IOException e)  
    28.         {  
    29.             System.out.println("ERROR: " + e);  
    30.         }  
    31.         System.out.println("count: " + count);  
    32.     }  
    33.   
    34.     /*** 
    35.      * 从原jar路径提取相应的类到目标路径,如将java/lang/CharSequence类从rt目录提取到rt1目录 
    36.      * @param string 提取类的全路径 
    37.      * @return 
    38.      * @throws IOException 
    39.      */  
    40.     public boolean copyClass(String string) throws IOException  
    41.     {  
    42.         String classDir = string.substring(0,string.lastIndexOf("/"));  
    43.         String className = string.substring(string.lastIndexOf("/")+1,string.length()) + ".class";  
    44.           
    45.         boolean result =false;  
    46.           
    47.         for(String jar : jarArr){  
    48.             File srcFile = new File(source + "/"+jar+"/" + classDir + "/" + className);  
    49.             if(!srcFile.exists())  
    50.             {  
    51.                 continue;  
    52.             }  
    53.               
    54.             byte buf[] = new byte[256];  
    55.             FileInputStream fin = new FileInputStream(srcFile);  
    56.   
    57.             /* 目标目录不存在,创建 */  
    58.             File destDir = new File(dest + "/"+jar+"1/" + classDir);  
    59.             if(!destDir.exists())  
    60.                 destDir.mkdirs();  
    61.   
    62.             File destFile = new File(destDir + "/" + className);  
    63.             FileOutputStream fout = new FileOutputStream(destFile);  
    64.             int len = 0;  
    65.             while((len = fin.read(buf)) != -1)  
    66.             {  
    67.                 fout.write(buf,0,len);  
    68.             }  
    69.             fout.flush();  
    70.             result = true;  
    71.             break;  
    72.         }  
    73.         return result;  
    74.     }  
    75. }  

    然后在将提取的class文件打包成jar文件,利用jar命令进行打包,然后替换以前的jar文件,这样lib就从以前的六十多M到几M多有,如图:

    这样我们就完成了jre的瘦身!

  • 相关阅读:
    docker 安装redis监控redis-stat
    maven 项目依赖打包 提示 package com.。。。。。 does not exist
    docker 建立跨主机网络
    docker-compose 安装mongodb集群==多台服务器
    docker 安装mongodb集群==多台服务器
    博客将近一年半没有更新了
    elasticsearch 使用同义词
    《SpringBoot第一篇:HelloWorld启蒙》
    go学习路线资料
    docker和k8s的概念-IaaS、PaaS、SaaS 的区别
  • 原文地址:https://www.cnblogs.com/ggds/p/7716346.html
Copyright © 2020-2023  润新知