jvm--3.內存管理


5.JVM內存管理
JAVA虛擬機在執行java程序的過程中,會把它管理的內存分成若干個不同的數據區域。
------------------------------------------------------------------------------------—
| 運行時數據區 |
| ----------- -------- ----------------- |
| | 方法區 | | 棧 | | 本地方法棧 | |
| | | | | | | |
| ----------- -------- ----------------- |
| |
| --------------------------- ----------------- |
| | 堆 | | 程序計數器 | |
| | | | | |
| --------------------------- ----------------- |
| ?? ?? ?? ?? |
| ---------------------------- ------------------ ----------------- |
| | 執行引擎 | | 本地庫接口 | ?? | 本地方法庫 | |
| | | | | | | |
| ---------------------------- ------------------ ----------------— |
|
| 其中,堆和方法區,是所有線程共有區;
| 棧,本地方法棧,程序計數器,是線程私有區。
|------------------------------------------------------------------------------------
(1) 內存區域
a.程序計數器(Program Counter Register),線程私有,不會拋出任何內存異常
I.可以這么理解,當前線程所執行字節碼的行號指示器。字節碼解釋器,就是通過程序計數器的值,來選取下一條要執行的字節碼指令(分支、循環、跳轉等基礎功能都需要依賴計數器)。
II.java虛擬機的多線程是通過,各個線程之間輪流切換并分配內存來實現的。在任何一個確定的時刻,一個處理器都只會執行一條線程中的指令。因此,為了線程切換回來之后能夠
恢復到正確的執行位置。每條線程都需要一個獨立的程序計數器。
III.如果線程正在執行的是一個java方法,計數器記錄的是正在執行的虛擬機字節碼指令的地址;
如果正在執行的是native方法,計數器的值為空。

b.java虛擬機棧 (Java Virtual Machine Stack) , 線程私有,會有 StackOverFlow 和 OutOfMemoryError異常 ,通過-Xss分配內存大小
I.每個方法在執行時,都會創建一個棧幀(Stack Frame),用于存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。
每一個方法從調用到執行完成的過程,就對應一個 棧幀 在虛擬機棧中,入棧到出棧的過程。

II.棧中的局部變量表,所需的內存空間,在編譯器間完成分配。在進入一個方法時,這個方法需要在幀(Stack Frame) 中分配多大的內存空間是確定的,在這個方法運行期間,
不會 改變 局部變量表 所占用 內存空間 的大小。

III.當java啟動一個線程時,虛擬機會計算出這個線程所需要的棧深度,(比如10),當線程請求的棧深度(每調一個方法壓一個棧幀,用掉一個棧深度),大于虛擬機給Stack分配的
棧深度,會拋出StackOverFlow異常。(用javap javap -verbose Test 查看程序的字節碼,Code 屬性, stack=2 , 可以查看運行的詳細過程,包括棧深度,和每個棧幀需要多少個slot)
當一個可擴展棧(棧有可擴展的有固定長度的,由使用的JAVA虛擬決定的),動態擴展時,無法請求到足夠的內存(比如我需要10M內存,但是JVM只給我5M),會拋出,
OutOfMemoryError異常。

c.本地方法棧 (Native Method Stack) ,線程私有,會有 StackOverFlow 和 OutOfMemoryError異常,通過-Xss分配內存大小
I.和java虛擬機棧基本一樣。區別不過是,
JVM Stack 為 虛擬機 執行java方法 服務;
Native Method Stack 為 虛擬機 執行本地方法服務
II.也會拋出StackOverFlow 和 OutOfMemoryError異常

d.java堆 , 線程共享 , 會拋出OutOfMemoryError異常。,通過-Xms分配內存最小值,-Xmx分配內存最大值
I.存放 對象實例 和 數組。
II.是垃圾回收的主要區域。
III. java堆,可以處于物理上的不連續空間,邏輯上連續即可。可動態擴展,通過-Xms控制大小。
IV.如果堆中沒有完成內存分配,并且堆也無法擴展是,將會拋出OutOfMemoryError異常。

e.方法區 , 線程共享 , 會拋出OutOfMemoryError異常。
I.用于存儲,已經被虛擬機加載的,類的信息、常量、靜態變量、編譯后的代碼等數據
II.不需要連續的內存,可以選擇固定大小和可擴展
III.當方法區無法完成內存分配需求時,會拋出OutOfMemoryError異常。
e-slave. 運行時常量池,會拋出OutOfMemoryError異常。
是方法區的一部分。
I.Class文件中,除了有類的 版本、 字段、方法、接口、等描述信息外,還有一項就是常量池(Constant Pool Table),用于存放編譯期生成的,
各種字面變量和符號引用(),這部分將在類加載后進入方法區的常量池。
II.并非預置在Class文件中常量池中的內容,才能進入方法區;運行期間也可能將新的常量放入池中。

f.直接內存,并不是java虛擬機內存的一部分,而是機器內存的一部分,會拋出OutOfMemoryError異常
I.NIO引入了一種類似于 通道(Channel) 和 緩沖區(Buffer) ,可以使用Native函數庫直接分配堆外內存。
然后,通過一個存儲在java堆中的,DirectByteBuffer對象作為這塊內存的引用進行操作。
這樣避免了在java堆和native堆中來回復制數據,提高了性能。
II.當直接內存和JVM內存之和大于機器內存時,拋出OutOfMemoryError內存。

(2)對象創建細節
a.內存分配方式
I.指針碰撞, 如果java堆中內存是絕對規整的,為對象分配空間的任務,等同于把一塊確定大小的內存從java堆中劃分出來。
如果java堆中內存是絕對規整的,所有用過的內存放在一邊,空閑的內存放在另一邊,中間放著一個指針作為臨界點,那么分配內存就是,
把指針向空閑空間那邊挪動等同于對象大小的距離,這種分配方式成為 指針碰撞。

II.空閑列表, 如果內存是不規則的,虛擬機就必須維護一個表,記錄那些內存塊是可用的,分配的時候找到一塊足夠大的內存塊分給對象實例,
并更新列表的記錄,這種方式稱為 空閑列表(Free List)

b.選擇哪種分配方式是java堆是否規整決定的,java堆是否規整,是由采用的垃圾收集器是否帶有壓縮功能決定的。因此,
使用Serial、ParNew燈光帶有壓縮(Compact)過程的收集器時,系統采用的分配算法是指針碰撞。
使用CMS這種基于 Mark-Sweep(標記-移除) 算法的收集器,系統采用的分配算法是空閑列表。

c.空閑列表問題,及解決方案
問題:
首先,堆是線程共有的,所以,當多線程創建對象是,有這樣一個問題,當Thread A分配一塊內存完成后,還沒更新列表,這時Thread B給
自己的對象分配了同一塊內存,這就造成了沖突。
方案:
I.對分配內存的動作,進行同步,這種造成性能下降。
II.每個線程在堆中,預先分配一小塊內存作為緩沖區,稱為(Thread Local Allocation Buffer , TLAB) ,哪個線程需要給自己的對象分配
內存,就在自己的TLAB上分配,只有自己的TLAB上分配完了,才需要同步鎖定。通過-XX:+/-UseTLAB參數來設定。(性能調優)

d.內存分配完成后,虛擬機將分配到的內存空間初始化為零值。這一步操作保證了Java代碼中可以不賦初始值就可以使用

e.接下來,虛擬機對對象進行必要的設置,例如這個對象是哪個類的實例、對象的hash-code、對象的GC分代年齡,等信息。存在對象頭中。
這樣從JVM的角度來說,對象創建完成。

f.對象的內存布局,對象在內存中的存儲可以分為3塊區域:
I.對象頭 (Header) : 包括兩部分信息,
第一部分,存儲對象自身運行時數據,如HashCode,GC分代年齡,鎖定狀態標志,線程持有的鎖。
第二部分,類型指針,即對象指向它的 類 元數據的指針,虛擬機通常用這個指針確定對象屬于哪個類。
還有記錄數組長度的信息。
II.實例數據 (Instance Data) : 程序定義的個字段的內容。包括父類和子類。
III.對齊填充 (Padding) : 占位符,換句話說,就是保證對象大小必須是 8字節(byte) 的整數倍

g.對象的訪問定位
java程序需要使用棧上面的reference,引用數據來操作堆上的具體對象。
I. 句柄
這種方式,Java堆中會分配一塊內存,作為句柄池,reference存儲的就是對象句柄池地址。
句柄中包含了對象實例數據 (在堆上),和類型數據(類數據,在常量池)具體地址信息。
好處:GC后reference不需要修改
II.直接指針
reference存儲的就是對象地址。
好處:速度快,節省了一次指針定位開銷。
Sun HotSpot使用直接指針
(3)堆溢出,OutOfMemoryError 后面跟 Heap
-Xms 和 -Xmx 設置堆的最大和最小內存
堆的最小參數 -Xms 和 最大參數 -Xmx 設置為一樣,就可以避免堆擴展。
a.解決思路:
I.用內存映像分析工具(如,Eclipse Memory Analyzer) 堆Dump出來的堆轉儲快照進行分析。
II.分析的重點是確認內存中的對象是否是必要的,即先確認是否有 內存泄漏(Memory Leak,當創建
的對象沒有使用,又無法被GC回收,就是內存泄漏)
III.如果是內存泄漏,查看泄漏對象到GC Roots的引用鏈信息,就能找到泄漏對象是通過怎樣的路徑與GC Roots相關聯,
并導致GC無法自動回收他們的。通過引用鏈信息,定位到泄漏代碼的位置,review代碼。
IV.如果沒有內存泄漏,即,內存中的對象都必須存活。那就看虛擬機堆參數(-Xms和-Mmx)和內存相比,看是否還可以調大。
從代碼上檢查是否有,某些對象生命周期過長,持有時間過長的情況,嘗試優化這些代碼,從而減少運行期的內存消耗。
(4)棧溢出 StackOverFlow
-Xss設置棧占用內存大小。默認1024K,也就是1M
a.虛擬機啟動時,有棧大小的默認參數,當所有的棧幀(Stack Frame),內存加起來超過棧內存大小時,就會拋出StackOverFlow異常。
在棧深度,默認情況下,大多數棧深度達到1000-2000幀沒有問題,對于普通遞歸是夠用了(但是棧幀大小是不確定的,所以,只能是大多數情況下。)
b.建立線程數量過多,導致內存溢出
I.操作系統,分配給每個進程的內存是有限制的。如果給一個java分配了1G內存,
虛擬機提供了參數,來控制堆和方法區所占用內存大小,如果沒有指定棧占用的內存大小,忽略其它,剩余的內存 1G - 堆內存 - 方法區內存,被本地方法棧和虛擬機棧
瓜分,棧是線程私有的,棧分配的內存越大,可以建立的線程數就越少,建立新線程時候,容易把剩下的內存耗盡。這種情況,可以減少最大堆,和減少棧容量,換取更多
的線程,避免內存溢出。
(5)方法區,內存溢出 。OutOfMemoryError后面跟隨PermGen
-XX:PerSize 和 -XX:MaxPermSize限制方法區大小
String.intern()是一個native方法,作用:如果字符串常量池中,已經包含一個等于此String 對象的字符串,則返回常量池中,代表此字符串的對象。
否則,將此String對象添加到常量池中。
a.Spring Hibernate在對類進行增強時,都會使用到CGLib這類字節碼技術,增強的類越多,就需要越大的方法區,容易導致方法區的內存溢出。
b.JSP第一次運行時,要編譯成java類,大量的jsp也有可能導致方法區內存溢出。

(6) 本機直接內存溢出 OutOfMemoryError Unsafe.allocateMemory
DirectMemory 容量可以通過:-XX:MaxDirectMemorySize指定,如果不指定,則默認與java堆最大值 (-Xmx)一樣。
如果內存溢出,在堆的Dump文件很小,或者沒有明顯的異常,又或者程序中使用了NIO,可以考慮是 本機直接內存溢出。

轉載于:https://www.cnblogs.com/fubaizhaizhuren/p/5938480.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/254280.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254280.shtml
英文地址,請注明出處:http://en.pswp.cn/news/254280.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[BZOJ2458][BeiJing2011]最小三角形

題目描述 Description Xaviera現在遇到了一個有趣的問題。平面上有N個點,Xaviera想找出周長最小的三角形。由于點非常多,分布也非常亂,所以Xaviera想請你來解決這個問題。為了減小問題的難度,這里的三角形也包括共線的三點。 輸…

Makefile中的變量

Makefile中的變量 2007-11-03 12:03Makefile中變量有以下幾個特征: 1. Makefile中變量和函數的展開(除規則命令行中的變量和函數以外),是在make讀取makefile文件時進行的,這里的變量包括了使用“”定義和使用指示符“d…

小技巧集錦

2019獨角獸企業重金招聘Python工程師標準>>> jackson JsonDeserialize 使用方法&#xff1a; 實現方法注解寫在set方法上。 public class CustomJsonDateDeserializer extends JsonDeserializer<Date> {private SimpleDateFormat datetimeFormat new SimpleD…

interface-C#接口-統一的標準

文章目錄接口的定義接口的實現實例1實例2接口的繼承博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 接口是面向對象編程的一個重要技術&#xff0c;在C#中負責實現多重繼承。一個接口定義一個協定&#xff0c;實現接口類或結構體必須遵守其協定…

JMeter入門(1):JMeter總體介紹及組件介紹

一、JMeter概述 JMeter就是一個測試工具&#xff0c;相比于LoadRunner等測試工具&#xff0c;此工具免費&#xff0c;且比較好用&#xff0c;但是前提當然是安裝Java環境&#xff1b;JMeter可以做(1)壓力測試及性能測試&#xff1b;(2)數據庫測試&#xff1b;(3)Java程序的測試…

二層交換機、三層交換機和路由器的基本工作原理和三者之間的主要區別

二層交換機:二層交換技術是發展比較成熟&#xff0c;二層交換機屬數據鏈路層設備&#xff0c;可以識別數據包中的MAC地址信息&#xff0c;根據MAC地址進行轉發&#xff0c;并將這些MAC地址與對應的端口記錄在自己內部的一個地址表中。 具體如下&#xff1a; &#xff08;1&…

Unity3D:視物有點眩暈的原因

設置Main Camera 的 Field of View 為100&#xff0c;看物體總覺得很不舒服。 設置為 60 就正常了。 根本原因&#xff0c;有待于分析 轉載于:https://www.cnblogs.com/makebetter/p/7063694.html

使用jQuery清空file文件域的解決方案

使用jQuery清空file文件域的解決方案 var file $("#file") file.after(file.clone().val("")); file.remove();

更改mysql最大連接數

方法一&#xff1a; 打開cmd&#xff0c;用"mysql -u root -p;"命令進入mysql, 輸入命令&#xff1a;show variables like "max_connections" 顯示最大連接數 更改最大連接數 : set global max_connections 5000 方法二&#xff1a; 在my.ini加上 max_co…

根據HTML5 獲取當前位置的經緯度【百度地圖】【高德地圖】

是想讓地圖的定位用戶位置更準確一些。 查看了介紹&#xff1a; http://www.w3school.com.cn/html5/html_5_geolocation.asp 看介紹中拿數據挺簡單。 <!DOCTYPE html> <html> <body> <p id"demo">點擊這個按鈕&#xff0c;獲得您的坐標&…

C#抽象類與密封類-abstract-sealed

文章目錄抽象類和抽象方法實現抽象方法接口、類和抽象類密封類博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 如果說繼承是面向對象設計理論的基石&#xff0c;那么抽象理論和方法就是繼承理論的頂梁柱。 抽象類和抽象方法 簡單的說&#x…

vs2010快捷鍵

Ctrl M O: 折疊所有方法 Ctrl M M: 折疊或者展開當前方法 Ctrl M L: 展開所有方法 1、強迫智能感知&#xff1a;CtrlJ&#xff1b;2、強迫智能感知顯示參數信息&#xff1a;Ctrl-Shift-空格&#xff1b;3、格式化整個塊&#xff1a;CtrlKF4、檢查括號匹配(在左右括號間切…

startup畢業論文

今天起得相對比較晚&#xff0c;為的是一個沒有目的面試&#xff0c;去了的結果。只是打擊一下自己的自信心&#xff0c;走的時候&#xff0c;面試官冷冷的說了一句&#xff0c;你的面試到此結束&#xff0c;是的&#xff0c;我并沒有很傷心&#xff0c;在門外等面試的時候&…

Javascript實現信息滾動效果的方法

<html><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title>向上無縫滾動</title><style>body { font-size: 12px; line-height: 24px; text-algin: center; /* 頁面內容居中 */}* { ma…

C# delegate與event,委托與事件

文章目錄委托示例事件實例博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 委托和事件是C#中兩個比較復雜的概念&#xff0c;這篇文章介紹兩個概念與基本用法&#xff0c;讓大家理解C#中的事件處理機制。 委托 委托也叫代理&#xff0c;就是把…

路由器與交換機的工作原理

路由器與交換機的工作原理 計算機網絡往往由許多種不同類型的網絡互連連接而成。如果幾個計算機網絡只是在物理上連接在一起&#xff0c;它們之間并不能進行通信&#xff0c;那么這種“互連”并沒有什么實際意義。因此通常在談到“互連”時&#xff0c;就已經暗示這些相互連接的…

Java的四種引用,強弱軟虛,用到的場景(轉+補充)

Q1&#xff1a;引用隊列是什么&#xff1f;如何使用&#xff1f;使用的場景有哪些&#xff1f; A1:oracle的api文檔的描述&#xff1a; https://docs.oracle.com/javase/7/docs/api/java/lang/ref/ReferenceQueue.htmlReference queues, to which registered reference objects…

C# lambda表達式與匿名方法

文章目錄匿名方法Lambda表達式實例實例博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 C#中的匿名方法是在C#2.0引入的&#xff0c;它終結了聲明委托的唯一方法是使用命名方法的時代。在C#更高版本中&#xff0c;Lambda表達式取代了匿名方法&a…

LINUx打包命令匯總

.tar 解包&#xff1a;tar xvf FileName.tar 打包&#xff1a;tar cvf FileName.tar DirName &#xff08;注&#xff1a;tar是打包&#xff0c;不是壓縮&#xff01;&#xff09; ——————————————— .gz 解壓1&#xff1a;gunzip FileName.gz 解壓2&#xff1a;…

常用的相似度計算

在數據分析和數據挖掘的過程中&#xff0c;我們經常需要知道個體間差異的大小&#xff0c;進而評價個體的相似性和類別。最常見的是數據分析中的相關分析&#xff0c;數據挖掘中的分 類和聚類算法&#xff0c;如K最近鄰&#xff08;KNN&#xff09;和K均值&#xff08;K-Means&…