Java高級特征運行時數(shù)據(jù)區(qū)域
運行時數(shù)據(jù)區(qū)域包括程序計數(shù)器、java虛擬機棧、本地方法棧、java堆和方法區(qū)。
程序計數(shù)器:當前線程所執(zhí)行的字節(jié)碼的行號指示器,改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令;java虛擬機多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式實現(xiàn),線程切換后能恢復到正確的執(zhí)行位置,所以線程私有;native方法的計數(shù)器為空
java虛擬機棧:線程私有,生命周期與線程相同,每個方法被執(zhí)行的時候會創(chuàng)建一個棧幀用于存儲局部變量表、操作棧、動態(tài)鏈接、方法出口等,一個方法調(diào)用完成的過程就是從入棧到出棧的過程。一般說的棧就是虛擬機棧中的局部變量表,存放編譯期可知的各種基本數(shù)據(jù)(boolean、byte、char、short、int、float、long、double)、對象引用和returnAdress類型。局部變量表所需的內(nèi)存空間在編譯期間完成分配(完全確定分配多大內(nèi)存),在運行期間不會改變局部變量表的大小,最小單位Slot,每個slot可重用,虛擬機通過索引定位的方式使用局部變量表
本地方法棧:跟虛擬機棧作用相似,虛擬機棧為虛擬機執(zhí)行java方法服務,而本地方法棧則為虛擬機使用的native方法服務,sun hotspot虛擬機直接就把兩者合二為一
java堆:被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機啟動的時候創(chuàng)建,唯一目的就是存放對象實例;主流虛擬機都是按照可擴展來實現(xiàn)(通過-Xmx和-Xms控制),如果堆中沒有內(nèi)存完成實例分配,并且堆也無法再擴展時將會拋出OutOfMemoryError異常
方法區(qū):線程共享的內(nèi)存區(qū)域,用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù);有時稱為永久代,這個區(qū)域的內(nèi)存回收目標主要針對常量池的回收和對類型的卸載。運行時常量池是方法區(qū)的一部分,用于存放編譯期生成的各種字面量和符號引用,將在類加載后存放到方法區(qū)的運行時常量池中;具備動態(tài)性,運行期間也可能將新的常量放入池中(如string類的intren()方法)
主流對象訪問方式主流對象訪問方式:使用句柄和直接指針。
使用句柄,java堆中會將劃分出一塊內(nèi)存來作為句柄池,reference中存儲的就是對象的句柄地址,句柄中包含了對象實例數(shù)據(jù)(java堆)和類型數(shù)據(jù)(方法區(qū))各自的具體信息地址;
直接指針,reference中存儲的就是對象地址,節(jié)省了一次指針定位時間的開銷,速度更快
垃圾收集垃圾收集:主要指java堆跟方法區(qū),前面三個區(qū)域都隨線程而生而滅,內(nèi)存在編譯期具備確定性,方法或者線程結束就回收了。
堆一般回收一次70-95%,方法區(qū)(永久代)主要回收廢棄常量和無用的類
判斷對象是否存活:
-引用計數(shù)算法:給對象中添加一個引用計數(shù)器,每當有一個地方引用時加1,當引用失效時減1,任何時刻計數(shù)器都為0的對象就是不可能再被使用(java沒有采用這種方法,因為很難解決對象之間的相互循環(huán)引用問題)。
-根搜索算法:通過一系列的名為“GC Roots”的對象作為起始點,從這些節(jié)點開始向下搜索,搜索所走過的路徑稱為引用鏈,當一個對象的GC Roots沒有任何引用鏈相連時,證明此對象是不可用的;java中可作為GC Roots的對象有:虛擬機棧中的引用對象,方法區(qū)中類靜態(tài)屬性引用的對象,方法區(qū)中的常量引用的對象,本地方法棧中JNI(Native方法)的引用的對象
jdk1.2后分為強引用、軟引用、弱引用、虛引用;只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象;軟引用描述一些有用但非必需的對象,其關聯(lián)的對象在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前列進回收范圍之中并進行第二次回收;弱引用也是描述非必需對象,只能生存到下一次垃圾收集發(fā)生之前;虛引用對其生存時間不構成影響,也無法通過虛引用取得一個對象實例,為一個對象設置虛引用關聯(lián)的唯一目的就是希望能在這個對象被收集器回收時收到一個系統(tǒng)通知。
判斷一個無用的類判斷一個無用的類:該類所有的實例都已經(jīng)被回收,java堆中不存在該類的任何引用;加載該類的ClassLoader已經(jīng)被回收;該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射該類的方法
垃圾收集算法標記-清除算法:首先標記出所有需要回收的對象,在標記完成后統(tǒng)一回收掉所有被標記的對象;缺點:效率低,產(chǎn)生大量不連續(xù)內(nèi)存碎片占有內(nèi)存。
復制算法:將內(nèi)存按容量劃分大小相等兩塊,每次只使用其中一塊,一塊用完后就將還存活的對象復制到另一塊,然后再把已使用的內(nèi)存空間一次清理掉。
缺點:需要更大內(nèi)存;商業(yè)虛擬機采用此方法回收新生代:分為一塊較大的Eden空間和兩塊小的Survivor空間,每次使用Eden和其中的一塊Survivor,回收時將這兩塊還存活的對象一次性拷貝到另一塊Survivor空間,最后清理掉Eden和剛才用過的Survivor空間;Eden:Survivor大小默認8:1,如果另一塊Survivor沒有足夠的空間就直接通過分配機制進入年老代。
標記-整理:讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內(nèi)存;回收年老代。
分代收集算法:根據(jù)對象存活周期的不同將內(nèi)存劃分為幾塊。
對象優(yōu)先對象優(yōu)先在Eden分配,當沒有足夠空間的時候虛擬機發(fā)起一次minor gc。
大對象直接進入老年代,大對象是指需要大量連續(xù)內(nèi)存空間的java對象。
長期存活的對象將進入老年代。
部署程序高性能硬件上部署程序,主要有兩種方式
)通過64位jdk來使用大內(nèi)存
)使用若干個32位虛擬機建立邏輯集群來利用硬件資源
集群間錯誤集群間同步導致的內(nèi)存溢出
堆外內(nèi)存導致的溢出錯誤
外部命令導致系統(tǒng)緩慢
服務器jam進程崩潰
jps:虛擬機進程狀況工具,可以列出正在運行的虛擬機進程,并顯示虛擬機執(zhí)行主類的名稱
jstat:虛擬機統(tǒng)計信息監(jiān)視工具,顯示本地或遠程虛擬機進程中的類裝載、內(nèi)存、垃圾收集、jit編譯等運行數(shù)據(jù)
jinfo:java配置信息工具,實時查看和調(diào)整虛擬機各項參數(shù)
jmap:java內(nèi)存映像工具,用于生成堆轉(zhuǎn)儲快照(dump文件),還可以查詢finalize執(zhí)行隊列,java堆和永久代的信息
jhat:虛擬機堆轉(zhuǎn)儲快照分析工具
jstack:java堆棧跟蹤工具,生成虛擬機當前時刻的線程快照,用于定位線程出現(xiàn)長時間停頓的原因
加載和連接java中類型的加載和連接過程都是在程序運行期間完成的
類的整個生命周期:加載、驗證、準備、解析、初始化、使用、卸載
加載:
通過一個類的全限定名來獲取定義此類的二進制字節(jié)流
將這個字節(jié)流所代表的靜態(tài)存儲結構轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結構
在java堆中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這些數(shù)據(jù)的訪問入口
驗證:連接階段的第一步,為了確保Class文件中的字節(jié)流中包含的信息符合當前虛擬機的要求,且不會危害虛擬機自身安全。
文件格式驗證、元數(shù)據(jù)驗證、字節(jié)碼驗證和符號引用驗證四個階段。
準備:正式為類變量分配內(nèi)存并設置類變量初始值的階段,這些內(nèi)存都將在方法區(qū)中進行分配(不包括實例變量的初始化,它將在對象實例化的時候分配在java堆中)。
解析:虛擬機將常量池內(nèi)的符號引用替換為直接引用的過程
初始化:執(zhí)行類構造器()方法的過程
類加載器類加載器:啟動類加載器、擴展類加載器、應用程序類加載器
執(zhí)行引擎虛擬機字節(jié)碼執(zhí)行引擎(解釋執(zhí)行、編譯執(zhí)行)
編譯過程javac編譯過程:解析與填充符號表過程;插入式注解處理器的注解處理過程;分析與字節(jié)碼生成過程
解析與填充符號表:
1)詞法語法分析:詞法分析是將源代碼的字符流轉(zhuǎn)變?yōu)闃擞洠═oken)集合,語法分析是根據(jù)Token序列來構造抽象語法樹的過程;
2)填充符號表:符號表由一組符號地址和符號信息構成的表格,可用于語義檢查,地址分配的依據(jù)
注解處理器:在處理注解期間對語法樹進行修改,編譯器將回到解析及填充符號表的過程重新處理
語義分析與字節(jié)碼生成:語義分析的主要任務是對結構上正確的源程序進行上下文有關性質(zhì)的審查,分為標注檢查和數(shù)據(jù)及控制流分析兩個步驟;通常使用語法糖能夠增加程序的可讀性,減少代碼出錯的機會;字節(jié)碼生成是java編譯過程最后一個階段,把語法樹、符號表等轉(zhuǎn)化成字節(jié)碼寫到磁盤中
解釋器和編譯器當程序需要迅速啟動和執(zhí)行的時候,解釋器可以首先發(fā)揮作用,省去編譯的時間,立即執(zhí)行;當程序運行后,隨著時間推移,編譯器逐漸發(fā)揮作用,把越來越多的代碼編譯成本地代碼之后,可以獲取更高的執(zhí)行效率。
hotspot虛擬機內(nèi)置量兩個即時編譯器client compiler和server compiler,采用分層編譯的策略。
“熱點代碼”會被即時編譯器編譯:被多次調(diào)用的方法;被多次執(zhí)行的循環(huán)體。熱點探測:基于采樣;基于計數(shù)器(方法調(diào)用計數(shù)器,回邊計數(shù)器)。
即時編譯器編譯優(yōu)化技術
1)方法內(nèi)聯(lián):除去方法調(diào)用成本,為其他優(yōu)化建立良好基礎
2)進行冗余訪問消除
3)復寫傳播
4)無用代碼消除
5)公共子表達式消除
6)數(shù)組邊界檢查消除
7)逃逸分析
Java內(nèi)存模型Java內(nèi)存模型:屏蔽各種硬件和操作系統(tǒng)的內(nèi)存訪問差異,以實現(xiàn)讓java程序在各種平臺下都能達到一致的并發(fā)效果。
主內(nèi)存與工作內(nèi)存:每條線程的工作內(nèi)存保存了該線程使用到的變量的主內(nèi)存副本拷貝,線程對變量的所有操作都必須在工作內(nèi)存中進行
內(nèi)存間交互操作內(nèi)存間交互操作:lock(鎖定)、unlock(解鎖)、read(讀?。?、load(載入)、use(使用)、assign(賦值)、store(存儲)、write(寫入)
volatile:一個變量定義成volatile之后,具備兩種特性,第一是保證此變量對所有線程的可見性;但并發(fā)下并一定是安全的,因為java里面的運算操作并非原子操作,由于volatile變量只能保證可見性,在不符合以下兩條規(guī)則的運算場景中,仍需要通過加鎖(使用synchronized或java.util.concurrent中的原子類)來保證原子性。
1)運算結果并不依賴變量的當前值,或者確保只有單一的線程修改變量值
2)變量不需要與其他狀態(tài)變量共同參與不變約束
第二個特性是禁止指令重排序優(yōu)化。volatile變量的讀操作的性能消耗與普通變量幾乎沒啥差別,但是寫操作可能會慢一些,因為需要在本地代碼中插入許多內(nèi)存屏障指令來保證處理器不發(fā)生亂序執(zhí)行,在volatile與鎖中選擇的唯一判斷依據(jù)僅僅是volatile的語義能否滿足使用場景的需求
允許虛擬機將沒有被volatile修飾的64位數(shù)據(jù)的讀寫操作劃分為兩次32位的操作來進行,即允許虛擬機實現(xiàn)選擇可以不保證64位數(shù)據(jù)類型的load、store、read、write這四個操作的原子性,這就是所謂的long或double的非原子性協(xié)定,目前商用虛擬機幾乎把64位數(shù)據(jù)的讀寫操作作為原子操作來對待
java內(nèi)存模型圍繞在并發(fā)過程中如何處理原子性、可見性和有序性三個特性來建立的。
可見性:(volatile、synchronized和final修飾)
有序性:線程內(nèi)表現(xiàn)為串行的語義,觀察另一個線程則是無序的
線程的實現(xiàn)線程的實現(xiàn)主要有三種方式:使用內(nèi)核線程實現(xiàn),使用用戶線程實現(xiàn),使用用戶線程加輕量級進程混合實現(xiàn)
一條java線程就映射到一條輕量級進程之中,線程調(diào)度是指系統(tǒng)為線程分配處理器使用權的過程,主要調(diào)度
方式有兩種:協(xié)同式線程調(diào)度和搶占式線程調(diào)度,java使用搶占式,java線程是被映射到操作系統(tǒng)的原生線程上來實現(xiàn)的,線程調(diào)度最終還是由操作系統(tǒng)說了算
java進程5個狀態(tài),任一時刻有且只有一種狀態(tài):新建、運行、無限期等待、限期等待、阻塞、結束
java中各種操作共享的數(shù)據(jù)分為五類:不可變、絕對線程安全、相對線程安全、線程兼容和線程對立
線程安全的實現(xiàn)方法:互斥同步(悲觀)、非阻塞同步(樂觀)、無同步方案
鎖優(yōu)化
1)自旋鎖與自適應自旋
2)鎖消除
3)鎖粗化
4)輕量級鎖
5)偏向鎖
Beand的高級特征Spring程序中,Java Bean一般與Spring是非耦合的,不會依賴于Spring類庫。這也是Spring的優(yōu)點。1
實現(xiàn)BeanNameAware接口獲取本bean的id屬性BeanNameAware中一個方法setBeanName(String arg0);它會在bean所有參數(shù)設置后 init-method之前調(diào)用,在bean中聲明一個屬性接受。
獲取BeanFactory實現(xiàn)BeanFactoryAware可以獲取該bean對應的BeanFactory。
demo:
View Code
實現(xiàn)DisposableBean接口執(zhí)行銷毀方法。
被bean中的destory-method屬性替代,一般不使用
實現(xiàn)InitializingBean接口執(zhí)行初始化方法。
被bean的init-method屬性替代,一般不使用
BeanFactory對象BeanFactory對象的幾個常用的方法:
boolean containsBean(String):判斷指定名稱的Bean是否存在
Object getBean(String):返回指定名稱的Bean。如果沒有,會拋出異常
Object getBean(String,Class):返回指定名稱的Bean,并進行類型轉(zhuǎn)換成類對象。兩個過程中出錯都會異常
boolean isSingleton(String):判斷指定名稱的Bean是否配置為singleton。沒有bean,拋出異常
String[] getAliases(String):獲取指定名稱bean的所有別名的數(shù)組
屬性覆蓋器對于一些參數(shù),更實用更簡單的方法是使用properties配置,而不是配置在Spring的配置文件中。Spring提供屬性替代屬性,允許把某些屬性配置在properties文件中。
配置PropertyOverrideConfigurer屬性覆蓋器
PropertyOverrideConfigure允許把XML配置里的魔偶寫參數(shù)配置到properties文件中。這些在數(shù)據(jù)庫配置中很常用。配置時需要配置一個PropertyOverrideConfigure對象,指定properties文件的位置,然后把替換的屬性用形如${jdbc.url}的字符串替代。
Pro/ENGINEER高級特征Pro/ENGINEER的高級特征實現(xiàn)了復雜曲面的數(shù)字化表示,使難以描述的復雜模型變得直觀明了而且非常精確。利用Pro/ENGINEER的零件高級建模功能可以設計外形復雜的產(chǎn)品,從機械產(chǎn)品中的彈簧、螺紋到工業(yè)造型設計中的手機外殼、顯示器等,都離不開高級特征的使用??梢哉f,Pro/ENGINEER的高級特征對工業(yè)造型設計人員來說是必不可少的得力助手,它大大提高了產(chǎn)品設計的效率和質(zhì)量。
螺旋掃描螺旋掃描,即用一個截面沿著螺旋軌跡掃描來創(chuàng)建特征,它通過旋轉(zhuǎn)曲面的輪廓和螺距兩者來定義軌跡。螺旋軌跡和旋轉(zhuǎn)曲面只是一種作圖工具,它們不會出現(xiàn)在生成的特征中。
螺旋掃描功能可用于實體伸出、實體切口、薄殼伸出和切口,以及曲面及曲面修剪等特征。從主菜單〖插入〗|〖螺旋掃描〗|〖伸出〗,在〖屬性〗菜單中,對成對出現(xiàn)的命令(只能選擇其一)進行選擇來定義螺旋掃描特征。
? 〖常量〗螺距為常數(shù)。
? 〖變量〗螺距是可變的,并由某圖形定義。
? 〖穿過軸〗橫截面位于穿過旋轉(zhuǎn)軸的平面內(nèi)。
? 〖軌跡法向〗確定橫截面方向,使之垂直于軌跡或旋轉(zhuǎn)面。
? 〖右手定則〗使用右手定則定義軌跡,即右旋。
? 〖左手定則〗使用左手定則定義軌跡,即左旋。
可變剖面掃描可變剖面掃描允許截面沿所選的多條軌跡運動來創(chuàng)建特征,截面在運動過程中其形狀沿著軌跡線變化。多條軌跡線中,一條軌跡線控制截面的運動路線,其他幾條軌跡線控制截面的形狀,截面在運動過程中,并一定垂直于軌跡線。
使用可變剖面掃描功能,必須先繪制軌跡線。然后從主菜單〖插入〗|〖變剖面掃描〗,或從工具欄中選擇按鈕,彈出可變剖面掃描操控板??蛇M行實體的伸出和切除、曲面及修剪、薄殼等特征。
〖參照〗用于選取軌跡線及對截面運動的控制方式,點擊彈出上滑面板。
掃描混合命令掃描混合命令使用一條軌跡線與幾個剖面來創(chuàng)建一個實體特征,同時具有掃描和混合的效果。
選擇主菜單〖插入〗|〖螺旋掃描〗|〖伸出〗,出現(xiàn)圖7.28所示的菜單管理器。 掃描混合的截面放置方式與可變截面掃描相似:
垂直于原始軌跡:截面垂直于原始軌跡線上該截面放置點的切矢量,即確定Z軸。
軸心方向:截面垂直于原始軌跡線,并沿指定的方向掃描。