JVM內存結構和Java數據類型

Java是一門面向對象編程語言,由Sun公司於20世紀90年代開發,後來被Oracle公司收購,此語言不僅吸收了C++語言的各種優點,還摒棄了C++裏難以理解的多繼承、指針等概念,因此Java語言具有功能強大和簡單易用兩個特徵。Java語言作爲靜態面向對象編程語言的代表,極好地實現了面向對象理論,允許程序員以優雅的思維方式進行復雜的編程。
Java具有簡單性、面向對象、分佈式、健壯性、安全性、平臺獨立與可移植性、多線程、動態性等特點。Java可以編寫桌面應用程序、Web應用程序、分佈式系統和嵌入式系統應用程序等。
也正是因爲Java的語言的跨平臺,適合網絡編程,易用,健壯,穩定和智能(GC),以及強大的生態,又加上近幾年移動開發的興起,而在移動開發領域佔據80%市場的Android系統主要是基於Java語言開發,才讓這門僅僅誕生20年的語言成功蟬聯高級開發語言排行榜的王座數年之久,直至筆者寫這篇文章之時,Java還是處在Tiobe開發語言排行榜榜首。當然這一切JVM功不可沒,本文將從虛擬機的角度切入,闡述Java的數據類型。
一、什麼是JVM
 JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。
Java語言的一個非常重要的特點就是與平臺的無關性。而使用Java虛擬機是實現這一特點的關鍵。一般的高級語言如果要在不同的平臺上運行,至少需要編譯成不同的目標代碼。而引入Java語言虛擬機後,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。這就是Java的能夠“一次編譯,到處運行”的原因,通常本文所講的虛擬機指代Oracle官方的”HotSpot虛擬機“。
所以從本質上來講,Java也是一種解釋型語言,由Java源程序編譯成Class二進制流文件,然後由虛擬機JIT引擎動態編譯成目標機器的機器語言執行。
二、什麼時候需要JVM
所有的Java程序都依賴JVM執行,當Java程序運行時,JVM通過main方法作爲程序的入口,依次加載Class文件解析執行,並分配一個獨立的JVM內存空間。
三、在什麼地方安裝JVM
所有需要執行Java程序的設備都需要安裝JRE。
JRE顧名思義是java運行時環境,包含了java虛擬機,java基礎類庫。是使用java語言編寫的程序運行所需要的軟件環境,是提供給想運行java程序的用戶使用的。
JDK包含了JRE,同時還包含了編譯java源碼的編譯器javac,還包含了很多java程序調試和分析的工具:jconsole,jvisualvm等工具軟件,還包含了java程序編寫所需的文檔和demo例子程序。
四、JVM的內存分配模型
通常大家都習慣把JVM的內存分爲三個區域:堆區、棧區、方法區。下面我將爲各位詳細的說明各個內存區域所承擔的職責:
1 、方法區。
方法區是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息(class info)、常量(constant)、靜態變量(static 修飾的變量)、即時編譯器(JIT)編譯後的代碼等數據。雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,但是它卻有一個別名叫Non-Heap(非堆),目的應該是爲了跟Java堆區分別開來。
2 、堆區。
Java堆(Java Heap)是Java虛擬機所管理的內存中最大的一塊。Java堆是被所有線程共享的一塊內存區域,在虛擬機啓動時創建。此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這裏分配內存。這一點在Java虛擬機規範中的描述是:所以的對象實例以及數組都要在堆上分配內存,但是隨着JIT編譯器的發展和逃逸分析技術的逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化,所有的對象都分配到堆上並不那麼絕對了。Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱作“GC堆”。
3 、棧區。
Java虛擬機棧(Java vcirtual Machine Stacks)也線程私有的,它的生命週期和線程一樣。虛擬機棧描述的是Java方法執行的內存模型:每個方法在執行的同時都會創建一個棧幀(stack frame)用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每個方法從調用直到執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。
4 、本地方法棧。
本地方法棧(Native Method Stack)與虛擬機棧所發揮的作用是非常相似的,它們之間的區別不過是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則爲虛擬機使用到Native方法服務。在虛擬機規範中對本地方法棧中方法使用的語言、使用方式與數據結構並沒有強制規定,因此具體的虛擬機可以自由實現它。甚至有的 虛擬機(譬如Sun HotSpot)直接就把本地方法棧和虛擬機棧合二爲一。與虛擬機棧一樣,本地方法棧區域也會跑出Stack Overflow 和 OutOfMemoryError異常。
5 、程序計數器。
程序計數器(Program Counter Register )是一塊較小的內存空間,他可以看作是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型中(僅僅是概念模型,各種虛擬機的實現可能回通過一些更高效的方式去實現),字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支,循環,跳轉,異常處理。線程恢復等基礎功能都需要依賴這個計數器來完成。
當然JVM的內存模型不僅僅只包含這幾塊,還有常量池(包含在方法區)等。
從上述內存模型,我們也大概知道線程的安全模型問題,例如典型棧區是線程不共享的,相對線程安全,其他區線程不一定線程安全,當然Java也提供一系列的機制來保證線程安全。
Java 的數據類型
在講Java數據類型之前先科普一下我們經常在開發中表達內存容量大小的單位:位 (bit)、字節(byte),字符(char)
通常一個“標準字符”是 1字節 = 8位 ,爲什麼叫標準字符呢?因爲計算機科學最初是由西方世界發展起來的,他們的語言中最小單元就是一個英文字母也就是一個字符,所以就定義成一個字節存一個字符,當然隨着計算機科學的發展,發現一個字節根本存不下其他語種的最小符號,例如漢字,所以就有了“標準字符”的說法。
一 、 Java基本數據類型
byte :佔用 8 位存儲空間,最大存儲的數據量是255,存放的數據範圍是-128~127之間 。
short :佔用16位存儲空間,最大存儲的數據量是65536,數據範圍是-32768~32767之間 。
int :佔用32位存儲空間,最大存儲的數據量是2的32次方-1,數據範圍是-2的32次方~2的32次方-1 。
long : 佔用64位存儲空間,最大存儲的數據量是2的64次方-1,數據範圍是-2的64次方~2的64次方-1 。
float :佔用32位存儲空間,數據範圍在3.4e-45~1.4e38,直接賦值時必須在數字後加上f或F。
double : 佔用64位存儲空間,數據範圍在4.9e-324~1.8e308,賦值時可以加d或D也可以不加。
boolean : 佔用一位儲存空間, 只有true和false兩個取值。
char : 佔用16位存儲空間,存儲Unicode碼,用單引號表示。

注意:在Java中浮點類型默認是double的,即2.00和1.10在計算機裏轉換進行二進制存儲,這就涉及到數據精度,出現這個現象的原因正式浮點型數據的精度問題。所以通常我們不用float和double類型進行比較,對於精度要求較高的商業系統,我們通常使用BigDecimal對象來進行表示。

float a = 2.00 - 1.10  打印的結果不是期待的0.9 ,而是 0.8999999 。
要想正常打印: 必須在數字後面加個 f 。
二 、Java 引用類型
String :用雙引號表示,存儲字符串。

Array : 數組類型。

Object : 對象類型。
等 。。。 當然引用類型又包含,強引用,弱引用,虛引用,本文就不再闡述了,感興趣的同學自行查閱相關資料。
很多人說Java的參數傳遞既有值傳遞,又有引用傳遞其實是不對的,我們都知道Java是沒有的指針的說法,Java的棧區存放對象的內存地址,所以我們如果用
System.print.out(); 打印對象的話,通常控制檯打印的是一串看不懂的hash 碼,如果要打印對象信息只能通過調用對象的toString()的方法進行打印 。在Java裏面只有值傳遞,對於基本數據類型,方法的形參傳遞的是實參值,對於引用類型,傳遞的是實參的內存地址,所以很多同學就誤以爲Java 既有值傳遞又有引用傳遞 。


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