垃圾收集 java_Java的内置垃圾收集如何使您的生活更美好(大部分时间)
垃圾收集 java
通過從您的應用程序學習企業APM產品,發現更快,更有效的性能監控。 參加AppDynamics APM導覽!
“無需為用戶編寫將寄存器返回到自由存儲列表的程序。”
這條線(以及隨后的十幾條線)被埋在約翰·麥卡錫(John McCarthy)具有里程碑意義的論文中 ,該論文發表于1960年,“符號表達式的遞歸函數及其由機器進行的計算”。這是對自動內存的第一個已知描述。管理。
在指定如何在Lisp中管理內存時,McCarthy能夠排除顯式的內存管理。 因此,麥卡錫(McCarthy)減輕了開發人員對手動內存管理的煩惱。 使這個故事真正令人驚奇的是,這幾個詞激發了其他人將某種形式的自動內存管理(也稱為垃圾收集 (GC))整合到此后開發的四分之三的更廣泛使用的語言和運行時中。 該列表包括兩個最受歡迎的平臺,即Java的虛擬機 (JVM)和.NET的公共語言運行時 (CLR)以及Google即將推出的Go Lang 。 GC不僅存在于大型企業中,還存在于移動平臺上,例如Android的Dalvik,Android Runtime和Apple的Swift。 您甚至可以在Web瀏覽器以及諸如SSD之類的硬件設備上找到運行的GC。 讓我們探討一些為什么行業更喜歡自動化而不是手動內存管理的原因。
自動內存管理的開端
那么,麥卡錫如何設計自動內存管理? 首先,Lisp引擎將Lisp表達式分解為子表達式,每個S表達式都存儲在鏈接列表中的單個單詞節點中。 節點是從空閑列表中分配的,但是不必將它們返回到空閑列表,直到它為空。
一旦空閑列表為空,運行時就會跟蹤鏈接列表并標記所有可到達的節點。 接下來,它掃描包含所有節點的緩沖區,并將未標記的節點返回到空閑列表。 重新填寫自由列表后,應用程序將繼續。
今天,這被稱為單空間,就地跟蹤垃圾收集。 該實現非常簡單:它只需要處理一個非循環定向圖,其中所有節點的大小都完全相同。 只有一個線程運行,并且該線程執行了應用程序代碼或垃圾回收器。 相比之下,當今JVM中的收集器必須應對循環和節點大小不一致的有向圖。 JVM是多線程的,在多核CPU(可能是多插槽的主板)上運行。 因此,今天的實現要復雜得多,以至于GC專家很難預測任何給定情況下的性能。
進度緩慢:垃圾回收暫停時間
當Lisp垃圾收集器運行時,應用程序停止了。 在Lisp的初始版本中,收集器通常占用30%到40%的CPU周期。 在1960年代的硬件上,這可能導致應用程序停頓幾分鐘,這被稱為“世界停止” 。 好處是分配幾乎對應用程序吞吐量(完成的有用工作量)沒有任何影響。 此實現突出顯示了暫停時間和對應用程序吞吐量的影響之間的持續斗爭,這一斗爭一直持續到今天。
通常,收集器的暫停時間特性越好,它對應用程序吞吐量的影響就越大。 Java當前的所有實現都帶有暫停時間/開銷成本。 并行收集具有較長的暫停時間和較低的開銷,而大多數并發的收集器具有較短的暫停時間并消耗更多的計算資源(包括內存和CPU)。
任何GC實現者的目標都是最大程度地保證保證變種線程接收的最少處理器時間,這一概念稱為最小變種利用率(MMU)。 即使這樣,當前的GC開銷也可以很好地運行在5%以下,而在典型的C ++應用程序中,您會遇到15%到20%的開銷。
那么,為什么不像在Java應用程序中那樣感到這種開銷呢? 由于開銷在C / C ++運行時間中平均分布,因此最終用戶看不到它。 實際上,有關托管內存的最大抱怨是,它在無法預測的時間內暫停了您的應用程序不可預測的時間。
垃圾收集進展
Sun Java最初的垃圾收集器并沒有改善垃圾收集的形象。 它的單線程,單行距實現使應用程序停滯了很長時間,并極大地拖累了分配率。 直到Java 2才引入了代內存池方案(以及并行的(主要是并發的和增量的)收集器)。 盡管這些收集器提供了改進的暫停時間特性,但是暫停時間仍然是個問題。 而且,這些實現非常復雜,以致大多數開發人員不太可能具有調整它們的必要經驗。 為了使情況更加復雜,IBM,Azul和RedHat擁有一個或多個自己的垃圾收集器-每個垃圾收集器都有各自的歷史,優勢和怪癖。 此外,包括SAP,Twitter,Google,阿里巴巴在內的許多公司都擁有自己的內部JVM團隊,并帶有Garbage收集器的修改版本。
隨著時間的流逝,增加了備用且更復雜的分配路徑導致分配開銷圖片的巨大改進。 例如,JVM中的快速路徑分配現在比C / C ++中的典型分配快大約30倍。 麻煩之處在于:只有可以通過轉義分析測試的數據才有資格進行快速路徑分配。 (幸運的是,我們的絕大多數數據都通過了此測試,并從此備用分配路徑中受益。)
另一個優點是撤離收集器帶來的成本降低和成本模型簡化。 在這種方案中,收集器將實時數據復制到另一個內存池。 因此,不存在恢復短命數據的成本。 這并不是分配廣告惡心的邀請,因為每次分配都會產生成本,并且高分配率會觸發更頻繁的GC活動并累積額外的復制成本。 抽空收集器有助于提高GC的效率和可預測性,但是仍然存在大量資源成本。
那導致我們記憶。 內存管理要求您保留的內存至少是手動內存管理需要的五倍。 開發人員有時肯定知道應該釋放數據。 在這些情況下,顯式釋放而不是通過決策使收集者有理由便宜。 正是這些成本使蘋果最初選擇了Objective-C的手動內存管理。 在Swift中,Apple選擇使用引用計數。 他們為弱引用和自有引用添加了注釋,以幫助收集器應對循環引用。
還有其他無形的或難以衡量的成本可以歸因于運行時的設計決策。 例如,失去對內存布局的控制權可能導致應用程序性能受L2高速緩存未命中和高速緩存行密度的支配。 在這些情況下,性能下降很容易超過10:1。 未來實現者面臨的挑戰之一是如何更好地控制內存布局。
回顧一下當第一次將Lisp引入Lisp時GC的性能如何,以及通向目前狀態的漫長而又令人沮喪的道路,很難想象為什么任何構建運行時的人都想使用托管內存。 但是請考慮一下,如果您手動管理內存,則需要訪問底層的參考系統-這意味著該語言需要添加語法來操作內存指針。
依靠托管內存的語言始終缺乏管理指針所需的語法,因為可以保證內存一致性。 這保證了所有指針都將指向它們應指向的位置,而如果您碰巧踩了它們,則無需懸空(空)指針等待耗盡運行時間。 如果允許開發人員直接創建和操作指針,則運行時無法保證。 另外,將其從語言中刪除會消除間接性,這是開發人員更難掌握的概念之一。 漏洞經常是由于從事精神體操的開發人員需要處理許多競爭問題并弄錯而導致的。 如果這種混合包含通過應用程序邏輯進行推理,以及手動內存管理和不同的內存訪問模式,則錯誤可能會出現在代碼中。 實際上,依賴手動內存管理的系統中的錯誤是當今系統中最嚴重和最大的安全漏洞來源之一。
為了防止這些類型的錯誤,開發人員總是要問:“我是否仍然有可行的參考資料來阻止我釋放這些資料?” 這個問題的答案通常是“我不知道”。 如果將對這些數據的引用傳遞到系統中的另一個組件,則幾乎不可能知道是否可以安全地釋放內存。 眾所周知,指針錯誤會導致數據損壞,或者在最佳情況下會導致SIGSEGV。
從圖片中刪除指針往往會產生一個更具可讀性,更易于推理和維護的代碼。 GC知道何時可以回收內存。 此屬性使項目可以安全地使用第三方組件,這在使用手動內存管理的語言中很少發生。
結論
在最佳狀態下,內存管理可謂是一項繁瑣的簿記任務。 如果可以將內存管理排除在待辦事項之外,那么開發人員往往會提高工作效率,并產生更少的錯誤。 我們還已經看到,GC并不是萬能藥,因為它有其自身的一系列問題。 但值得慶幸的是,向更好的實現邁進的步伐還在繼續。
Go Lang的新收集器結合了引用計數和跟蹤功能,以減少開銷并最大程度地減少暫停時間。 Azul聲稱已通過大大降低暫停時間來解決GC暫停問題。 Oracle和IBM一直在致力于收集器,他們認為收集器更適合包含大量數據的超大堆。 RedHat已與Shenandoah展開競爭,Shenandoah的目標是從運行時間中完全消除暫停時間。 同時,Twitter和Google繼續改善現有的收藏家,因此它們繼續對新的收藏家具有競爭力。
通過從您的應用程序學習企業APM產品,發現更快,更有效的性能監控。 參加AppDynamics APM導覽!
翻譯自: https://www.javacodegeeks.com/2017/02/javas-built-garbage-collection-will-make-life-better-time.html
垃圾收集 java
總結
以上是生活随笔為你收集整理的垃圾收集 java_Java的内置垃圾收集如何使您的生活更美好(大部分时间)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: ddos攻击器手机版(ddos攻击防御科
- 下一篇: red hat 4.1.2_安装Red
