打開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文件:
/*
@author jarg
@TODO 舉例查看當前程序必需的dll文件
*/
import java.io.InputStreamReader;
import java.io.IOException;
public class Hello
{
public static void main(String[] args) throws IOException
{
InputStreamReader ir = new InputStreamReader(System.in);
System.out.println("Hello");
ir.read();
}
}
2、編譯、運行
3、360安全衛士 -> 功能大全 -> 進程管理器 右上角的顯示加載到當前選中進程中的dll(也可以用其它工具或者直接用tasklist命令導出)
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程序時所加載的所有類,如:
@echo off
C:/Java/jdk1.6.0_16/bin/java -jar -classpath lib/*.jar; -verbose:class printSoft.jar >> class.txt
pause
在class.txt文件中保存如下的信息:
[Loaded java.lang.Math from shared objects file]
[Loaded java.nio.charset.Charset$3 from C:\Java\jdk1.6.0_16\jre\lib\rt.jar]
[Opened C:\Java\jdk1.6.0_16\jre\lib\charsets.jar]
[Loaded sun.nio.cs.AbstractCharsetProvider from C:\Java\jdk1.6.0_16\jre\lib\rt.jar]
[Loaded sun.nio.cs.ext.ExtendedCharsets from C:\Java\jdk1.6.0_16\jre\lib\charsets.jar]
[Loaded java.lang.Class$1 from shared objects file]
[Loaded sun.reflect.ReflectionFactory$1 from shared objects file]
[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就剩下如下信息:
java/lang/Object
java/io/Serializable
java/lang/Comparable
java/lang/CharSequence
java/lang/String
java/lang/reflect/GenericDeclaration
.......
2、從現有的jar包中提取我們整理的class文件,然後打包成jar,最終取代原有的jar,下面是一個提取class的工具類:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class CopyClass
{
private String source = "C:\\Users\\lzp\\Desktop\\printSoft\\jre6\\lib\\"; // 類源目錄
private String dest = "C:\\Users\\lzp\\Desktop\\printSoft\\jre6\\lib\\"; // 類拷貝目的目錄
String[] jarArr = new String[]{"rt","charsets"};
/***
*
* @param source 類源目錄
* @param dest 類拷貝目的目錄
* @param jarArr 需要的提取的jar文件
*/
public CopyClass(String source,String dest,String[] jarArr){
this.source=source;
this.dest=dest;
this.jarArr=jarArr;
}
public static void main(String[] args)
{
String[] jarArr = new String[]{"rt","charsets"};
CopyClass obj = new CopyClass("C:\\Users\\lzp\\Desktop\\printSoft\\jre6\\lib\\",
"C:\\Users\\lzp\\Desktop\\printSoft\\jre6\\lib\\",jarArr);
obj.readAndCopy("C:\\Users\\lzp\\Desktop\\printSoft\\class.txt");
}
/***
* @param logName 提取class明細
*/
public void readAndCopy(String logName)
{
int count = 0; // 用於記錄成功拷貝的類數
try
{
FileInputStream fi = new FileInputStream(logName);
InputStreamReader ir = new InputStreamReader(fi);
BufferedReader br = new BufferedReader(ir);
String string = br.readLine();
while(string != null)
{
if(copyClass(string) == true)
count++;
else
System.out.println("ERROR " + count + ": " + string);
string = br.readLine();
}
}
catch (IOException e)
{
System.out.println("ERROR: " + e);
}
System.out.println("count: " + count);
}
/***
* 從原jar路徑提取相應的類到目標路徑,如將java/lang/CharSequence類從rt目錄提取到rt1目錄
* @param string 提取類的全路徑
* @return
* @throws IOException
*/
public boolean copyClass(String string) throws IOException
{
String classDir = string.substring(0,string.lastIndexOf("/"));
String className = string.substring(string.lastIndexOf("/")+1,string.length()) + ".class";
boolean result =false;
for(String jar : jarArr){
File srcFile = new File(source + "/"+jar+"/" + classDir + "/" + className);
if(!srcFile.exists())
{
continue;
}
byte buf[] = new byte[256];
FileInputStream fin = new FileInputStream(srcFile);
/* 目標目錄不存在,創建 */
File destDir = new File(dest + "/"+jar+"1/" + classDir);
if(!destDir.exists())
destDir.mkdirs();
File destFile = new File(destDir + "/" + className);
FileOutputStream fout = new FileOutputStream(destFile);
int len = 0;
while((len = fin.read(buf)) != -1)
{
fout.write(buf,0,len);
}
fout.flush();
result = true;
break;
}
return result;
}
}
然後在將提取的class文件打包成jar文件,利用jar命令進行打包,然後替換以前的jar文件,這樣lib就從以前的六十多M到幾M多有,如圖:
這樣我們就完成了jre的瘦身!