Runtime類
Runtime類描述的是一種執行時,在Java程式執行過程中,所有的java程式都一定要執行在JVM(虛擬機器)的程序中
有了JVM程序,就需要一種型別可以描述當前程序的相關環境以及與之相關的處理操作,即Java設計出了Runtime類
每個JVM的程序中都會自動包含有一個Runtime類的例項化物件,開啟Runtime類之後就可以看見相關文件
[檢視文件連結](java.base (Java SE 11 & JDK 11 ) (oracle.com))
每一個JavaDos文件應該按照"成員"、"構造"、"方法"的形式進行類的結構展示,而Runtime類的文件直接給出的是"方法"摘要
原因:Runtime類中的構造方法被隱藏了,是私有屬性的,因此可知Runtime類應該屬於單例設計模式如下:
(注意:若屬於多例設計模式,在新的開發版本中一定會使用列舉來描述)
private Runtime(){}
將Runtime類設定為單例設計模式,主要是因為每個JVM程序只需要提供一個Runtime類的例項化物件,所有和JVM有關的資訊實際上都在Runtime類中提供了操作。圖解如下:
雖然Runtime類是單例設計模式,但從本質上來講單例設計模式都會在內部提供一個獲取本類例項化物件的static方法,這個方法在Runtime類中也存在;Runtime類常用的處理方法如下:
方法名稱 | 型別 | 描述 |
---|---|---|
public static Runtime getRuntime() | 普通 | 獲取Runtime類的例項化物件 |
public static exec(String command) throws IOException | 普通 | 開啟新的子程序 |
public long maxMemory() | 普通 | 最大可用記憶體 |
public long totalMemor() | 普通 | 可用記憶體 |
public long freeMemory() | 普通 | 空餘記憶體 |
public void gc() | 普通 | 手工執行GC |
透過以上的方法列表可知,在Runtime類中可以直接透過exec()方法建立一個新的子程序,而如果想要對這個子程序進行控制,則可以依據Process類來完成!
例項1:透過Runtime類建立新程序
//Runtime類
public class Application {
public static void main(String[] args) throws Exception {
Runtime runtime = Runtime.getRuntime();//獲取Runtime類的物件例項
//每當透過Runtime啟動了一個程序之後實際上會返回一個程序物件
Process process = runtime.exec("notepad.exe");//開啟Windows系統中的記事本
Thread.sleep(2000);//程序執行2秒
process.destroy();//銷燬程序
}
}
例項2:觀察記憶體資料
在以後實際的專案開發過程中,對於Runtime類來講比較重要的操作就在於記憶體資訊的動態獲取,整個Java程式的正確執行都需要依靠記憶體的支援,如果記憶體不能保證正確執行環境,那麼程式就會出現嚴重的效能問題!!
//Runtime類
public class Application {
//2.觀察記憶體資料
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
System.out.println("【1】MaxMemory = "+ runtime.maxMemory());
System.out.println("【1】TotalMemory = "+ runtime.totalMemory());
System.out.println("【1】FreeMemory = "+ runtime.freeMemory());
}
}
執行結果如下:
【1】MaxMemory = 1875378176
【1】TotalMemory = 126877696
【1】FreeMemory = 124193056
注意:
-
MaxMemory預設是實體記憶體的四分之一,TotalMemory預設是實體記憶體的六十四分之一
如下圖為本機的實體記憶體:
-
以上程式碼可以直接返回具體的記憶體大小資料,返回的記憶體大小單位是位元組,在Java程式設計中,所有與檔案大小有關的操作都會與long資料型別進行定義;
-
整個JVM(虛擬機器)程序的可用最大記憶體(MaxMemory) > 預設的可用記憶體(TotalMemory,該值會發生改變,但最終不超過MaxMemory) > 空閒記憶體(FreeMemory)
-
如果空閒記憶體不足者TotalMemory也會進行動態的擴充(這種動態的擴充機制實際上是非常傷害程式的)
例項3:動態獲取記憶體資訊
public class Application {
//2.觀察記憶體資料
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
System.out.println("【1】垃圾產生前的記憶體資訊:MaxMemory = "+ runtime.maxMemory());
System.out.println("【1】垃圾產生前的記憶體資訊:TotalMemory = "+ runtime.totalMemory());
System.out.println("【1】垃圾產生前的記憶體資訊:FreeMemory = "+ runtime.freeMemory());
String message = "abcd";//定義字串
for(int x = 0;x < 20;x++){
message +=message + x +"\n";//產生大量的垃圾
}
//runtime.gc();//手工進行垃圾清除
System.out.println("【2】垃圾產生後的記憶體資訊:MaxMemory = "+ runtime.maxMemory());
System.out.println("【2】垃圾產生後的記憶體資訊:TotalMemory = "+ runtime.totalMemory());
System.out.println("【2】垃圾產生後的記憶體資訊:FreeMemory = "+ runtime.freeMemory());
}
}
執行結果如下:
【1】垃圾產生前的記憶體資訊:MaxMemory = 1875378176
【1】垃圾產生前的記憶體資訊:TotalMemory = 126877696 //注意變化
【1】垃圾產生前的記憶體資訊:FreeMemory = 124193056 //注意變化
【2】垃圾產生後的記憶體資訊:MaxMemory = 1875378176
【2】垃圾產生後的記憶體資訊:TotalMemory = 160432128 //注意變化
【2】垃圾產生後的記憶體資訊:FreeMemory = 94067232 //注意變化
透過當前程式執行可知,此時可以使用的堆記憶體空餘空間已經有所減少,隨著程式垃圾的產生一定會浪費大量的堆記憶體空間,這樣就可以透過Runtime類動態的獲取記憶體資訊!
報錯:
如果此時記憶體空間已經被垃圾空間嚴重佔滿了,並且來不及進行擴充,則會出現以下的報錯資訊,
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
- 這屬於記憶體溢位的問題
- 這種OOM問題需要透過JVM調優來完成
例項4:gc()呼叫
如果清除程式可能會存在大量的垃圾,那麼最佳做法就是進行垃圾清除,可以利用Runtime類中提供的gc()方法來完成此類操作!
當使用gc()進行垃圾清除之後可以發現空閒的空間已經被回收了,這樣可以便於後續程式的高效諮執行
public class Application {
//2.觀察記憶體資料
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
System.out.println("【1】垃圾產生前的記憶體資訊:MaxMemory = "+ runtime.maxMemory());
System.out.println("【1】垃圾產生前的記憶體資訊:TotalMemory = "+ runtime.totalMemory());
System.out.println("【1】垃圾產生前的記憶體資訊:FreeMemory = "+ runtime.freeMemory());
String message = "abcd";//定義字串
for(int x = 0;x < 20;x++){
message +=message + x +"\n";//產生大量的垃圾
}
runtime.gc();//手工進行垃圾清除
System.out.println("【2】GC呼叫後的記憶體資訊:MaxMemory = "+ runtime.maxMemory());
System.out.println("【2】GC呼叫後的記憶體資訊:TotalMemory = "+ runtime.totalMemory());
System.out.println("【2】GC呼叫後的記憶體資訊:FreeMemory = "+ runtime.freeMemory());
}
}
執行結果如下:
【1】垃圾產生前的記憶體資訊:MaxMemory = 1875378176
【1】垃圾產生前的記憶體資訊:TotalMemory = 126877696 //注意變化
【1】垃圾產生前的記憶體資訊:FreeMemory = 124193056 //注意變化
【2】GC呼叫後的記憶體資訊:MaxMemory = 1875378176
【2】GC呼叫後的記憶體資訊:TotalMemory = 160432128 //注意變化
【2】GC呼叫後的記憶體資訊:FreeMemory = 145912272 //注意變化
總結:
Java之中的所有GC屬於守護執行緒(守護執行緒是伴隨主執行緒而存在的),主要目的是進行垃圾的收集以及堆記憶體空間釋放
如果要進行gc的處理,在JVM(虛擬機器)程序中有兩種處理形式:
- 自動的垃圾收集(需要清除整個的JVM體系結構)
- 手工的垃圾收集(Runtime類中的gc()方法)