基于weber的齿轮啮合刚度计算
【實(shí)例簡介】
%注意求剛度的時(shí)候用k=F/delta,而不是用k=F/(B*delta)。
%數(shù)據(jù)來源:多篇參考文獻(xiàn)
%采用方法:Webster方法(材料力學(xué)方法)
%兩個(gè)都是外齒輪嚙合
%原理參考《機(jī)械原理》P184和P185
文件:590m.com/f/25127180-490658798-0ea727(訪問密碼:551685)
以下內(nèi)容無關(guān):
-------------------------------------------分割線---------------------------------------------
分代收集理論
理論支撐:
弱分代假說(Weak Generational Hypothesis):絕大多數(shù)對(duì)象都是朝生夕滅的。
強(qiáng)分代假說(Strong Generational Hypothesis):熬過越多次垃圾收集過程的對(duì)象就越難以消亡。
跨代引用假說(Intergenerational Reference Hypothesis):跨代引用相對(duì)于同代引用來說僅占極少數(shù)。
跨代引用假說的具體解決辦法是:在新生代上建立一個(gè)全局的數(shù)據(jù)結(jié)構(gòu)(該結(jié)構(gòu)被稱為“記憶集”,Remembered Set),這個(gè)結(jié)構(gòu)把老年代劃分成若干小塊,標(biāo)識(shí)出老年代的哪一塊內(nèi)存會(huì)存在跨代引用。此后當(dāng)發(fā)生Minor GC時(shí),只有包含了跨代引用的小塊內(nèi)存里的對(duì)象才會(huì)被加入到GC Roots進(jìn)行掃描。
各類收集名稱
部分收集(Partial GC):指目標(biāo)不是完整收集整個(gè)Java堆的垃圾收集,其中又分為:
新生代收集(Minor GC/Young GC):指目標(biāo)只是新生代的垃圾收集。
老年代收集(Major GC/Old GC):指目標(biāo)只是老年代的垃圾收集。目前只有CMS收集器會(huì)有單獨(dú)收集老年代的行為。另外請(qǐng)注意“Major GC”這個(gè)說法現(xiàn)在有點(diǎn)混淆,在不同資料上常有不同所指,讀者需按上下文區(qū)分到底是指老年代的收集還是整堆收集。
混合收集(Mixed GC):指目標(biāo)是收集整個(gè)新生代以及部分老年代的垃圾收集。目前只有G1收集器會(huì)有這種行為。
整堆收集(Full GC):收集整個(gè)Java堆和方法區(qū)的垃圾收集。
標(biāo)記-清除算法
算法分為“標(biāo)記”和“清除”兩個(gè)階段:首先標(biāo)記出所有需要回收的對(duì)象,在標(biāo)記完成后,統(tǒng)一回收掉所有被標(biāo)記的對(duì)象。標(biāo)記過程就是對(duì)象是否屬于垃圾的判定過程。它是最基礎(chǔ)的收集算法,后續(xù)的收集算法大多都是以標(biāo)記-清除算法為基礎(chǔ),對(duì)其缺點(diǎn)進(jìn)行改進(jìn)而得到的。
它的主要缺點(diǎn)有兩個(gè):
第一個(gè)是執(zhí)行效率不穩(wěn)定,如果Java堆中包含大量對(duì)象,而且其中大部分是需要被回收的,這時(shí)必須進(jìn)行大量標(biāo)記和清除的動(dòng)作,導(dǎo)致標(biāo)記和清除兩個(gè)過程的執(zhí)行效率都隨對(duì)象數(shù)量增長而降低;
第二個(gè)是內(nèi)存空間的碎片化問題,標(biāo)記、清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致當(dāng)以后在程序運(yùn)行過程中需要分配較大對(duì)象時(shí)無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。
標(biāo)記-復(fù)制算法
為了解決標(biāo)記-清除算法面對(duì)大量可回收對(duì)象時(shí)執(zhí)行效率低的問題,它將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊上面,然后再把已使用過的內(nèi)存空間一次清理掉。每次都是針對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,分配內(nèi)存時(shí)也就不用考慮有空間碎片的復(fù)雜情況,只要移動(dòng)堆頂指針,按順序分配即可。
這樣實(shí)現(xiàn)簡單,運(yùn)行高效,但這種復(fù)制回收算法的代價(jià)是將可用內(nèi)存縮小為了原來的一半。
現(xiàn)在的商用Java虛擬機(jī)大多都優(yōu)先采用了這種收集算法去回收新生代。因?yàn)樾律械膶?duì)象有98%熬不過第一輪收集,所以,當(dāng)然實(shí)際實(shí)現(xiàn)并不是1:1的比例來劃分新生代內(nèi)存空間。而是使用“Appel式回收”,具體做法是把新生代分為一塊較大的Eden空間和兩塊較小的 Survivor空間,每次分配內(nèi)存只使用Eden和其中一塊Survivor。發(fā)生垃圾搜集時(shí),將Eden和Survivor中仍然存活的對(duì)象一次性復(fù)制到另外一塊Survivor空間上,然后直接清理掉Eden和已用過的那塊Survivor空間。HotSpot虛擬機(jī)默認(rèn)Eden和Survivor的大小比例是8∶1,也即每次新生代中可用內(nèi)存空間為整個(gè)新生代容量的90%(Eden的80%加上一個(gè)Survivor的10%),只有一個(gè)Survivor空間,即10%的新生代是會(huì)被“浪費(fèi)”的。當(dāng)Survivor空間不足以容納一次Minor GC之后存活的對(duì)象時(shí),就需要依賴其他內(nèi)存區(qū)域(實(shí)際上大多就是老年代)進(jìn)行分配擔(dān)保(Handle Promotion),這些對(duì)象便將通過分配擔(dān)保機(jī)制直接進(jìn)入老年代。
標(biāo)記-整理算法
在對(duì)象存活率較高時(shí)就要進(jìn)行較多的復(fù)制操作,效率將會(huì)降低。更關(guān)鍵的是,如果不想浪費(fèi)50%的空間,就需要有額外的空間進(jìn)行分配擔(dān)保,以應(yīng)對(duì)被使用的內(nèi)存中所有對(duì)象都100%存活的極端情況,所以在老年代一般不能直接選用標(biāo)記-復(fù)制算法。
針對(duì)老年代對(duì)象的存亡特征有另外一種有針對(duì)性的“標(biāo)記-整 理”(Mark-Compact)算法,其中的標(biāo)記過程仍然與“標(biāo)記-清除”算法一樣,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活的對(duì)象都向內(nèi)存空間一端移動(dòng),然后直接清理掉邊界以外的內(nèi)存。
如果移動(dòng)存活對(duì)象,尤其是在老年代這種每次回收都有大量對(duì)象存活區(qū)域,移動(dòng)存活對(duì)象并更新所有引用這些對(duì)象的地方將會(huì)是一種極為負(fù)重的操作,而且這種對(duì)象移動(dòng)操作必須全程暫停用戶應(yīng)用程序才能進(jìn)行,這就更加讓使用者不得不小心翼翼地權(quán)衡其弊端了,像這樣的停頓被最初的虛擬機(jī)設(shè)計(jì)者形象地描述為“Stop The World”。
是否移動(dòng)對(duì)象都存在弊端,移動(dòng)則內(nèi)存回收時(shí)會(huì)更復(fù)雜,不移動(dòng)則內(nèi)存分配時(shí)會(huì)更復(fù)雜。從垃圾收集的停頓時(shí)間來看,不移動(dòng)對(duì)象停頓時(shí)間會(huì)更短,甚至可以不需要停頓,但是從整個(gè)程序的吞吐量來看,移動(dòng)對(duì)象會(huì)更劃算。HotSpot虛擬機(jī)里面關(guān)注吞吐量的Parallel Scavenge收集器是基于標(biāo)記-整理算法的,而關(guān)注延遲的CMS收集器則是基于標(biāo)記-清除算法的。
CMS收集器也會(huì)在內(nèi)存空間的碎片化程度已經(jīng)大到影響對(duì)象分配時(shí),采用標(biāo)記-整理算法收集一次,以獲得規(guī)整的內(nèi)存空間。
根節(jié)點(diǎn)枚舉
固定可作為GC Roots的節(jié)點(diǎn)主要在全局性的引用(例如常量或類靜態(tài)屬性)與執(zhí)行上下文(例如棧幀中的本地變量表)中,盡管目標(biāo)明確,但現(xiàn)在Java應(yīng)用越做越龐大,光是方法區(qū)的大小就常有數(shù)百上千兆,里面的類、常量等更是恒河沙數(shù),查找過程要做到高效并非一件容易的事情。迄今為止,所有收集器在根節(jié)點(diǎn)枚舉這一步驟時(shí)都是必須暫停用戶線程的。必須在一個(gè)能保障一致性的快照中才得以進(jìn)行——這里“一致性”的意思是整個(gè)枚舉期間執(zhí)行子系統(tǒng)看起來就像被凍結(jié)在某個(gè)時(shí)間點(diǎn)上,不會(huì)出現(xiàn)分析過程中,根節(jié)點(diǎn)集合的對(duì)象引用關(guān)系還在不斷變化的情況,若這點(diǎn)不能滿足的話,分析結(jié)果準(zhǔn)確性也就無法保證。
主流Java虛擬機(jī)都是準(zhǔn)確式垃圾收集,所以并不需要一個(gè)不漏地檢查完所有執(zhí)行上下文和全局的引用位置。在HotSpot 的解決方案里,是使用一組稱為OopMap的數(shù)據(jù)結(jié)構(gòu)來達(dá)到這個(gè)目的。OopMap 記錄了棧上本地變量和寄存器到堆上對(duì)象的引用關(guān)系。其作用是:收集器只要掃描這些OopMap就可以直接得知這些GC Roots,并不需要真正一個(gè)不漏地從執(zhí)行上下文等GC Roots開始查找。
安全點(diǎn)
在OopMap的協(xié)助下,HotSpot可以快速準(zhǔn)確地完成GC Roots枚舉,但是,可能導(dǎo)致引用關(guān)系變化,或者說導(dǎo)致OopMap內(nèi)容變化的指令非常多,如果為每一條指令都生成對(duì)應(yīng)的OopMap,那將會(huì)需要大量的額外存儲(chǔ)空間。HotSpot只是在“特定的位置”記錄 了這些信息,這些位置被稱為安全點(diǎn)(Safep oint)。有了安全點(diǎn)的設(shè)定,也就決定了用戶程序執(zhí)行時(shí) 并非在代碼指令流的任意位置都能夠停頓下來開始垃圾收集,而是強(qiáng)制要求必須執(zhí)行到達(dá)安全點(diǎn)后才能夠暫停。
因此,安全點(diǎn)的選定既不能太少以至于讓收集器等待時(shí)間過長,也不能太過頻繁以至于過分增大運(yùn)行時(shí)的內(nèi)存負(fù)荷。安全點(diǎn)位置的選取基本上是以“是否具有讓程序長時(shí)間執(zhí)行的特征”為標(biāo)準(zhǔn)進(jìn)行選定的,又因?yàn)槊織l指令執(zhí)行的時(shí)間都非常短暫,程序不太可能因?yàn)橹噶盍鏖L度太長這樣的原因而長時(shí)間執(zhí)行,所以“長時(shí)間執(zhí)行”的最明顯特征就是指令序列的復(fù)用,例如方法調(diào)用、循環(huán)跳轉(zhuǎn)、異常跳轉(zhuǎn)等都屬于指令序列復(fù)用,所以只有具有這些功能的指令才會(huì)產(chǎn)生安全點(diǎn)。(實(shí)際上還要加上所有創(chuàng)建對(duì)象和其他需要在Java堆上分配內(nèi)存的地方,這是為了檢查是否即將要發(fā)生垃圾收集,避免沒有足夠內(nèi)存分配新對(duì)象)
那如何在垃圾收集發(fā)生時(shí),讓所有線程都跑到最近的安全點(diǎn),然后停頓下來呢。有兩種方案可供選擇:搶先式中斷 (Preemptive Suspension)和主動(dòng)式中斷(Voluntary Suspension)。
搶先式中斷不需要線程的執(zhí)行代碼主動(dòng)去配合,在垃圾收集發(fā)生時(shí),系統(tǒng)首先把所有用戶線程全部中斷,如果發(fā)現(xiàn)有用戶線程中斷的地方不在安全點(diǎn)上,就恢復(fù)這條線程執(zhí)行,讓它一會(huì)再重新中斷,直到跑到安全點(diǎn)上。現(xiàn)在幾乎沒有虛擬機(jī)實(shí)現(xiàn)采用搶先式中斷來暫停線程響應(yīng)GC事件。
主動(dòng)式中斷的思想是當(dāng)垃圾收集需要中斷線程的時(shí)候,不直接對(duì)線程操作,僅僅簡單地設(shè)置一個(gè)標(biāo)志位,各個(gè)線程執(zhí)行過程時(shí)會(huì)不停地主動(dòng)去輪詢這個(gè)標(biāo)志,一旦發(fā)現(xiàn)中斷標(biāo)志為真時(shí)就自己在最近的安全點(diǎn)上主動(dòng)中斷掛起。輪詢標(biāo)志的地方和安全點(diǎn)是重合的。
安全區(qū)域
安全點(diǎn)機(jī)制保證了程序執(zhí)行時(shí),在不太長的時(shí)間內(nèi)就會(huì)遇到可進(jìn)入垃圾收集過程的安全點(diǎn)。但是如果程序不執(zhí)行,比如沒有分配處理器時(shí)間的情況,典型的場(chǎng)景便是用戶線程處于Sleep 狀態(tài)或者Blocked狀態(tài),這時(shí)候線程無法響應(yīng)虛擬機(jī)的中斷請(qǐng)求,不能再走到安全點(diǎn)去中斷掛起自己,虛擬機(jī)也顯然不可能等待線程重新被激活分配處理器時(shí)間。對(duì)于這種情況,就必須引入安全區(qū)域(Safe Region)來解決。
安全區(qū)域是指能夠確保在某一段代碼片段之中,引用關(guān)系不會(huì)發(fā)生變化,因此,在這個(gè)區(qū)域中任意地方開始垃圾收集都是安全的。我們也可以把安全區(qū)域看作被擴(kuò)展拉伸了的安全點(diǎn)。
當(dāng)用戶線程執(zhí)行到安全區(qū)域里面的代碼時(shí),首先會(huì)標(biāo)識(shí)自己已經(jīng)進(jìn)入了安全區(qū)域,那樣當(dāng)這段時(shí)間里虛擬機(jī)要發(fā)起垃圾收集時(shí)就不必去管這些已聲明自己在安全區(qū)域內(nèi)的線程了。當(dāng)線程要離開安全區(qū)域時(shí),它要檢查虛擬機(jī)是否已經(jīng)完成了根節(jié)點(diǎn)枚舉(或者垃圾收集過程中其他需要暫停用戶線程的階段),如果完成了,那線程就當(dāng)作沒事發(fā)生過,繼續(xù)執(zhí)行;否則它就必須一直等待,直到收到可以離開安全區(qū)域的信號(hào)為止。
記憶集與卡表(卡表是記憶集的一種實(shí)現(xiàn)方式)
記憶集是一種用于記錄從非收集區(qū)域指向收集區(qū)域的指針集合的抽象數(shù)據(jù)結(jié)構(gòu)。
解決對(duì)象跨代引用所帶來的問題,垃圾收集器在新生代中建立了名為記憶集(Remembered Set)的數(shù)據(jù)結(jié)構(gòu),用以避免把整個(gè)老年代加進(jìn)GC Roots掃描范圍。而在垃圾 收集的場(chǎng)景中,收集器只需要通過記憶集判斷出某一塊非收集區(qū)域是否存在有指向了收集區(qū)域的指針 就可以了,并不需要了解這些跨代指針的全部細(xì)節(jié)。那設(shè)計(jì)者在實(shí)現(xiàn)記憶集的時(shí)候,便可以選擇更為粗獷的記錄粒度來節(jié)省記憶集的存儲(chǔ)和維護(hù)成本。
一種稱為“卡表”(Card Table)的方式去實(shí)現(xiàn)記憶集,這也是目前最常用的一種記憶集實(shí)現(xiàn)形式,HotSpot虛擬機(jī)的卡表只是一個(gè)字節(jié)數(shù)組,字節(jié)數(shù)組CARD_TABLE的每一個(gè)元素都對(duì)應(yīng)著其標(biāo)識(shí)的內(nèi)存區(qū)域中一塊特定大小的內(nèi)存塊,這個(gè)內(nèi)存塊被稱作“卡頁”(Card Page)。一般來說,卡頁大小都是以2的N次冪的字節(jié)數(shù),HotSpot中使用的卡頁是2的9次冪,即512字節(jié)。一個(gè)卡頁的內(nèi)存中通常包含不止一個(gè)對(duì)象,只要卡頁內(nèi)有一個(gè)(或更多)對(duì)象的字段存在著跨代指針,那就將對(duì)應(yīng)卡表的數(shù)組元素的值標(biāo)識(shí)為1,稱為這個(gè)元素變臟(Dirty),沒有則標(biāo)識(shí)為0。在垃圾收集發(fā)生時(shí),只要篩選出卡表中變臟的元素,就能輕易得出哪些卡頁內(nèi)存塊中包含跨代指針,把它們加入GC Roots中一并掃描。
寫屏障
卡表如何維護(hù)呢?如果是解釋執(zhí)行,虛擬機(jī)用充分的介入空間,但如果是編譯執(zhí)行呢?經(jīng)過即時(shí)編譯后的代碼已經(jīng)是純粹機(jī)器指令流了,所以必須在機(jī)器碼層面把卡表的維護(hù)動(dòng)作放到每一次賦值操作中。
HotSpot通過寫屏障技術(shù)維護(hù)卡表狀態(tài)。寫屏障可以看作在虛擬機(jī)層面對(duì)“引用類型字段賦值”這個(gè)動(dòng)作的AOP切面,在引用對(duì)象賦值時(shí)會(huì)產(chǎn)生一個(gè)環(huán)形(Around)通知,供程序執(zhí)行額外的動(dòng)作,也就是說賦值的前后都在寫屏障的覆蓋范疇內(nèi)。在賦值前的部分的寫屏障叫作寫前屏障(Pre-Write Barrier),在賦值后的則叫作寫后屏障(Post-Write Barrier)。
當(dāng)然額外的環(huán)形增強(qiáng)來維護(hù)卡表會(huì)有性能開銷,但相比掃描整個(gè)非收集代的代價(jià)相比還是低很多。
此外卡表維護(hù)還會(huì)面臨多線程并發(fā)的偽共享,為了減少偽共享帶來的性能損失,虛擬機(jī)會(huì)判斷只有卡表元素未臟的情況下才去更新此卡表元素。可以通過UseCondCardMark參數(shù)開啟這一判斷,默認(rèn)是關(guān)閉的。
總結(jié)
以上是生活随笔為你收集整理的基于weber的齿轮啮合刚度计算的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。