目錄##
1.內(nèi)存屏障
2.關(guān)鍵字native
3.偽共享
4.線程Dump文件
5.內(nèi)存溢出
6.jvm 配置和參數(shù)
1.內(nèi)存屏障##
目前有4種屏障----
LoadLoad屏障:對于這樣的語句Load1; LoadLoad; Load2,在Load2及后續(xù)讀取操作要讀取的數(shù)據(jù)被訪問前矾睦,保證Load1要讀取的數(shù)據(jù)被讀取完畢秽褒。
StoreStore屏障:對于這樣的語句Store1; StoreStore; Store2坐搔,在Store2及后續(xù)寫入操作執(zhí)行前拳氢,保證Store1的寫入操作對其它處理器可見践剂。
LoadStore屏障:對于這樣的語句Load1; LoadStore; Store2孝偎,在Store2及后續(xù)寫入操作被刷出前映皆,保證Load1要讀取的數(shù)據(jù)被讀取完畢挤聘。
StoreLoad屏障:對于這樣的語句Store1; StoreLoad; Load2,在Load2及后續(xù)所有讀取操作執(zhí)行前捅彻,保證Store1的寫入對所有處理器可見组去。它的開銷是四種屏障中最大的。在大多數(shù)處理器的實現(xiàn)中步淹,這個屏障是個萬能屏障从隆,兼具其它三種內(nèi)存屏障的功能诚撵。
2.native##
"A native method is a Java method whose implementation is provided by non-java code."
java中,native關(guān)鍵字說明其修飾的方法是一個原生態(tài)方法
键闺,方法對應(yīng)的實現(xiàn)不是在當(dāng)前文件寿烟,而是在用其他語言(如C和C++)實現(xiàn)的文件中。Java語言本身不能對操作系統(tǒng)底層進行訪問和操作辛燥,但是可以通過JNI接口(Java Native Interfac)調(diào)用其他語言來實現(xiàn)對底層的訪問筛武。存在的必要:需要與java外的環(huán)境做交互,與jvm,操作系統(tǒng)交互得到更多的特性挎塌,sun的解釋器是C實現(xiàn)的,實現(xiàn)更好的交互徘六。
- 標識符native可以與所有其它的java標識符連用,但是abstract除外
- 一個native method方法可以返回任何java類型榴都,包括非基本類型待锈,而且同樣可以進行異常控制嘴高。
- 使用本地方法是有開銷的
**JVM怎樣使Native Method跑起來: **
當(dāng)一個類第一次被使用到時竿音,這個類的字節(jié)碼會被加載到內(nèi)存,并且只會回載一次拴驮。在這個被加載的字節(jié)碼的入口維持著一個該類所有方法描述符的list春瞬,這些方法描述符包含這樣一些信息:方法代碼存于何處,它有哪些參數(shù)莹汤,方法的描述符(public之類)等等快鱼。
如果一個方法描述符內(nèi)有native,這個描述符塊將有一個指向該方法的實現(xiàn)的指針纲岭。這些實現(xiàn)在一些DLL文件內(nèi),但是它們會被操作系統(tǒng)加載到j(luò)ava程序的地址空間线罕。當(dāng)一個帶有本地方法的類被加載時止潮,其相關(guān)的DLL并未被加載,因此指向方法實現(xiàn)的指針并不會被設(shè)置钞楼。當(dāng)本地方法被調(diào)用之前喇闸,這些DLL才會被加載,這是通過調(diào)用java.system.loadLibrary()
實現(xiàn)的询件。
JNI的書寫步驟如下:
a.編寫帶有native聲明的方法的Java類
b.使用javac命令編譯編寫的Java類
c.使用java -jni ****來生成后綴名為.h的頭文件
d.使用其他語言(C燃乍、C++)實現(xiàn)本地方法
e.將本地方法編寫的文件生成動態(tài)鏈接庫
注:
1.在C++中,你可以用extern "C"告知C++編譯器去調(diào)用一個C的函數(shù)宛琅。
2.http://blog.csdn.net/wike163/article/details/6635321
3.偽共享##
偽共享(false sharing)刻蟹,就是多個線程同時修改共享在同一個緩存行里的獨立變量,無意中影響了性能嘿辟。
當(dāng)核心1上的線程想更新X舆瘪,而核心2上的線程想更新Y片效,而X變量和Y變量在同一個緩存行中時;每個線程都要去競爭緩存行的所有權(quán)來更新變量英古。如果核心1獲得所緩存行的所有權(quán)淀衣,那么緩存子系統(tǒng)將會使核心2中對應(yīng)的緩存行失效,反之亦然召调。這會來來回回的經(jīng)過L3緩存膨桥,大大影響了性能。這種情況唠叛,就像多個線程同事競爭鎖的所有權(quán)一樣只嚣。如果互相競爭的核心位于不同的插槽,就要額外橫跨插槽連接玻墅,問題可能更加嚴重介牙。
典型的CPU微架構(gòu)有3級緩存, 每個核都有自己私有的L1, L2緩存.
解決偽共享的方法是通過補齊(Padding),使得每一條緩存行只存一個多線程變量澳厢。
參考:
http://www.it165.net/pro/html/201403/11104.html
http://coderplay.iteye.com/blog/1486649
4.線程Dump文件##
Dump文件是進程的內(nèi)存鏡像环础。可以把程序的執(zhí)行狀態(tài)通過調(diào)試器保存到dump文件中剩拢。
Dump文件是用來給驅(qū)動程序編寫人員調(diào)試驅(qū)動程序用的线得,這種文件必須用專用工具軟件打開,比如使用WinDbg打開徐伐。
線程dump出來的信息包含線程基本信息贯钩;線程的運行狀態(tài)、標識和調(diào)用的堆棧办素;調(diào)用的堆棧包含完整的類名角雷,所執(zhí)行的方法,如果可能的話還有源代碼的行數(shù)性穿。因此勺三,可以使用線程Dump文件來進行診斷一些問題, 包括線程阻塞需曾,CPU 使用率過高吗坚,JVM Crash,堆內(nèi)存不足和類裝載等呆万。
輸出的方法:
win下商源,在啟動程序的控制臺里敲: Ctrl - Break,線程的 dump會產(chǎn)生在標準輸出中
Linux 下谋减,你可以通過命令 kill -3 PID (Java 進程的進程 ID)來獲取 Java 應(yīng)用的 dump 文件牡彻。
5.內(nèi)存溢出##
1.什么是內(nèi)存溢出
內(nèi)存溢出是指應(yīng)用系統(tǒng)中存在無法回收的內(nèi)存或使用的內(nèi)存過多,最終使得程序運行要用到的內(nèi)存大于虛擬機能提供的最大內(nèi)存。
jvm管理的內(nèi)存大致包括三種不同類型的內(nèi)存區(qū)域:Permanent Generation space(永久保存區(qū)域)逃顶、Heap space(堆區(qū)域)讨便、Java Stacks(Java棧)充甚。
永久保存區(qū)域主要存放Class(類)和Meta的信息,Class第一次被Load的時候被放入PermGen space區(qū)域霸褒,Class需要存儲的內(nèi)容主要包括方法和靜態(tài)屬性伴找。
堆區(qū)域用來存放Class的實例(即對象),對象需要存儲的內(nèi)容主要是非靜態(tài)屬性废菱。每次用new創(chuàng)建一個對象實例后技矮,對象實例存儲在堆區(qū)域中,這部分空間也被jvm的垃圾回收機制管理殊轴。
而Java棧跟大多數(shù)編程語言包括匯編語言的棧功能相似衰倦,主要基本類型變量以及方法的輸入輸出參數(shù)。Java程序的每個線程中都有一個獨立的堆棧旁理。容易發(fā)生內(nèi)存溢出問題的內(nèi)存空間包括:Permanent Generation space和Heap space樊零。
2.引起內(nèi)存溢出的主要原因
1.內(nèi)存中加載的數(shù)據(jù)量過于龐大,如一次從數(shù)據(jù)庫取出過多數(shù)據(jù)孽文;
2.集合類中有對對象的引用驻襟,使用完后未清空,使得JVM不能回收芋哭;
3.代碼中存在死循環(huán)或循環(huán)產(chǎn)生過多重復(fù)的對象實體沉衣;
4.使用的第三方軟件中的BUG;
5.啟動參數(shù)內(nèi)存值設(shè)定的過小
3.解決內(nèi)存溢出的方法
第一步减牺,修改JVM啟動參數(shù)豌习,直接增加內(nèi)存。(-Xms拔疚,-Xmx參數(shù)一定不要忘記加肥隆。)
第二步,檢查錯誤日志稚失,查看“OutOfMemory”錯誤前是否有其它異诚镉欤或錯誤。
第三步墩虹,對代碼進行走查和分析,找出可能發(fā)生內(nèi)存溢出的位置憨琳。
4.三種類型
** OutOfMemoryError: PermGen space**
發(fā)生這種問題的原意是程序中使用了大量的jar或class诫钓,使java虛擬機裝載類的空間不夠,與Permanent Generation space有關(guān)篙螟。解決這類問題有以下兩種辦法:
增加java虛擬機中的XX:PermSize和XX:MaxPermSize參數(shù)的大小菌湃,其中XX:PermSize是初始永久保存區(qū)域大小,XX:MaxPermSize是最大永久保存區(qū)域大小遍略。如針對tomcat6.0惧所,在catalina.sh 或catalina.bat文件中一系列環(huán)境變量名說明結(jié)束處(大約在70行左右) 增加一行:
JAVA_OPTS=" -XX:PermSize=64M -XX:MaxPermSize=128m"清理應(yīng)用程序中web-inf/lib下的jar骤坐,如果tomcat部署了多個應(yīng)用,很多應(yīng)用都使用了相同的jar下愈,可以將共同的jar移到tomcat共同的lib下纽绍,減少類的重復(fù)加載。
OutOfMemoryError: Java heap space
發(fā)生這種問題的原因是java虛擬機創(chuàng)建的對象太多势似,在進行垃圾回收之間拌夏,虛擬機分配的到堆內(nèi)存空間已經(jīng)用滿了,與Heap space有關(guān)履因。解決這類問題有兩種思路:
檢查程序障簿,看是否有死循環(huán)或不必要地重復(fù)創(chuàng)建大量對象。找到原因后栅迄,修改程序和算法站故。
增加Java虛擬機中Xms(初始堆大小)和Xmx(最大堆大幸阌摺)參數(shù)的大小西篓。如:set JAVA_OPTS= -Xms256m -Xmx1024m
OutOfMemoryError:unable to create new native thread
這種錯誤在Java線程個數(shù)很多的情況下容易發(fā)生。
6.jvm 配置和參數(shù)##
-Xms 初始堆大小
-Xmx 最大堆大小
-Xmn 年輕代大小
-Xss 每個線程的堆棧大小
-XX:參數(shù)
具體的內(nèi)容參照下面的引文吧朗兵。
堆分配
JVM初始分配的內(nèi)存由-Xms指定污淋,默認是物理內(nèi)存的1/64;JVM最大分配的內(nèi)存由-Xmx指定余掖,默認是物理內(nèi)存的1/4寸爆。默認空余堆內(nèi)存小于40%時,JVM就會增大堆直到-Xmx的最大限制盐欺;空余堆內(nèi)存大于70%時赁豆,JVM會減少堆直到 -Xms的最小限制。因此服務(wù)器一般設(shè)置-Xms冗美、-Xmx
相等以避免在每次GC 后調(diào)整堆的大小魔种。
對象的堆內(nèi)存由稱為垃圾回收器的自動內(nèi)存管理系統(tǒng)回收。
Eden:存放新生的對象
Survivor Space:有兩個粉洼,存放每次垃圾回收后存活的對象
Old Generation:主要存放應(yīng)用程序中生命周期長的存活對象
JVM(采用分代回收的策略)节预,用較高的頻率對年輕的對象(young generation)進行YGC
,而對老對象(tenured generation)較少(tenured generation 滿了后才進行)進行Full GC
属韧。這樣就不需要每次GC都將內(nèi)存中所有對象都檢查一遍安拟。
非堆內(nèi)存分配
JVM使用-XX:PermSize
設(shè)置非堆內(nèi)存初始值,默認是物理內(nèi)存的1/64宵喂;由XX:MaxPermSize
設(shè)置最大非堆內(nèi)存的大小糠赦,默認是物理內(nèi)存的1/4。
GC不會在主程序運行期對PermGen Space進行清理,所以如果你的應(yīng)用中有很多CLASS(特別是動態(tài)生成類拙泽,當(dāng)然permgen space存放的內(nèi)容不僅限于類)的話,就很可能出現(xiàn)PermGen Space錯誤淌山。
參考:
JVM性能優(yōu)化
JVM參數(shù)設(shè)置、分析
GC策略&內(nèi)存申請顾瞻、對象衰老
HotSpot VM GC 的種類