java 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文件:

/*
@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的瘦身!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章