002_JVM內存結構及調優學習

1. 常遇到關於內存溢出的錯誤
        java.lang包下
        StackOverflowError 不多
        OutOfMemoryError: heap space(堆空間) 比較常見
        OutOfMemoryError: PermGen space 常常出現
       
java

2. Java虛擬機結構和屬性
        
        內存區域: 保存java類和對象的物理區域
        
        堆: Java的內存區域叫作堆(heap)
        
        堆被分紅3個區域:
            新域(young generation)、舊域(tenured generation)、永久域(perm generation)
            標記爲virtual的部分被保留下來,必要時才分配出去。
            
            新域: 有Eden和兩個救助空間survivor組成,新對象存放在Eden中
            
            舊域: 對象在兩個救助空間survivor之間移動,當它們足夠"老",可以被移入到保存生存期較長對象的舊域
            
            永久域: 在虛擬機的整個生存期都生存的對象
            
        經常使用虛擬機配置選項屬性
            
            -Xmx    Java Heap最大值,默認值爲物理內存的1/4,最佳設值應該視物理內存大小及計算機內其餘內存開銷而定;

            -Xms    Java Heap初始值,Server端JVM最好將-Xms和-Xmx設爲相同值,開發測試機JVM能夠保留默認值;

            -Xmn    Java Heap Young區大小,不熟悉最好保留默認值;

            -Xss    每一個線程的Stack大小,不熟悉最好保留默認值;
            
            具體實施查看 remark001_幾招搞定JVM內存設置.txt
       
算法

3. JVM垃圾回收機制,2種回收方法,7種垃圾收集器
        
        2種回收方法
            引用計數: 當應用程序引用某一對象的時候,JVM增長引用數,當引用超出範圍時,JVM減小引用數,
                            當某對象的引用數爲0時,即可以進行垃圾回收機制。(早期JVM的技術)
                
            對象引用遍歷(對象引用樹) => 目前大多數JVM技術
                    對象引用遍歷樹,是將對象引用關係構建成一棵樹,從一組根對象開始,沿着整個對象樹上的每條連接,
                        遞歸肯定可到達(reachable)的對象。若是某對象別的對象(至少一個)引用,則將它做爲垃圾收集起來。
                    在對象遍歷階段,GC必須記住哪些對象能夠到大,以便刪除不可到達的對象,這稱爲標記(marking)對象。
                    
        7種垃圾收集器
            標記-清除收集器(Serial收集器): 對遍歷對象圖進行遍歷,並標記可到達的對象,而後掃描對象以尋找未標記對象並釋放內存。
                該收集器通常使用單線程工做並中止其它操做。
                (你媽媽在打掃房間,會叫你出去等一會)
                
            標記-清除-壓縮收集器:
                與Serial收集器有相同的標記階段。在第二階段,把標記對象複製到堆棧的新域中以便壓縮堆棧。
                這種收集器也會中止其它操做。
                
            複製收集器: 它將堆棧分爲2個域,稱爲半空間,它每次僅使用一個半空間。
                GC運行時,JVM生成的新對象放在一個半空間中,將可到達對象複製到另外一個半空間中,從而壓縮堆棧。
                這種方法適用於短生存期的對象,持續複製長生存期的對象則致使效率下降。
                
            增量收集器: 把堆棧分爲多個域,每次僅從一個域收集垃圾。這會形成較小的應用程序中斷。
            
            分代收集器: 把堆棧分紅兩個或多個域,用以存放不一樣壽命的對象。JVM生成的新對象通常放在其中的某個域中。
                過一段時間,繼續存在的對象將得到使用期並轉入更長壽命的域中。
                分代收集器對不一樣域使用不一樣的算法以優化性能。
            
            併發收集器: 同時發生,與應用程序同時運行。該收集器在某一時刻通常不得不中止其它操做以完成特定任務,
                可是由於其它應用程序可進行後臺操做,因此中斷其它處理的實際時間大大下降。
            
            並行收集器: 使用某種傳統算法,並使用多線程並行執行它們的工做。在多CPU機器上使用多線程技術能夠顯著提升Java應用程序的可擴展性。
            
            解釋兩個名詞:併發和並行。
                這兩個名詞都是併發編程中的概念,在談論垃圾收集器的上下文語境中,他們能夠解釋爲:
                    並行(Parallel):指多條垃圾收集線程並行工做,但此時用戶線程仍然處於等待狀態。
                    併發(Concurrent):指用戶線程與垃圾收集線程同時執行(但不必定是並行的,可能會交替執行),
                        用戶程序繼續運行,而垃圾收集程序運行於另外一個CPU上。
                    
4. JVM內存區域配置: 堆區域、新域與舊域、永久區域(非堆內存)、新域子空間
        
        Sun的JVM使用的是分代收集器,它把堆分紅3個主要域: 新域與舊域、永久區域(也叫非堆內存分配).
            JVM生成的全部新對象放在新域、一旦對象經歷了必定數量的垃圾收集循環後,便得到使用期進入舊域。
            在永久域中JVM則存儲類和方法對象。
        
        Java虛擬機的配置選項有專門用於對這些域進行配置的屬性
            
            配置堆區域
                堆實質上就是新域+舊域的和,它表明這2個區域的內存大小。
                設置堆的初始大小和最大大小內存 128MB
                    java -Xms128m (其中s爲start )
                    java -Xmx128m (其中x爲max )
                
                一般能夠將初始化大小設置爲最大大小,這樣能夠避免程序動態增長堆的大小。
                
            配置新域和舊域
                
                設置新域大小64MB
                    java -Xms256m -Xmx256m -Xmn64m  (Xmn 其中n爲new)
                    
                設置新域的初始值和最大值 64MB
                    (-XX:NewSize 設置新域初始值 )
                    (-XX:MaxNewsize 設置新域最大值 )
                    java -Xms256m -Xmx256m -XX:NewSize 64m -XX:MaxNewsize=64m
                
                設置了新域的大小,舊域大小即爲堆的大小減去新域的大小,不須要對舊域進行設置,JVM也沒有提供對舊域設置屬性。
                
            配置永久域(非堆內存)
                
                永久域默認大小爲4MB,運行程序時,JVM會調整永久域大小以知足須要。
                爲了不調整,可以使用-XX:PermSize設置初始值,使用-XX:MaxPermSize設置最大值
                    java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m
                    
            配置新域子空間
                
                默認狀態,JVM在新域使用複製收集器,對舊域使用標記-清除-壓縮收集器。
                在新域
            
        JVM內存區域配置的實戰案例: remark002_eclipse內存溢出崩潰_服務器JVM崩潰.txt    
    
5. JVM性能調優
    
        調優配置參考
                
            JVM的堆大小決定了JVM花費在收集垃圾上的時間和頻度。
            
            應用中創建和釋放對象的速度決定了垃圾收集的頻度。
            
            編程中,注意使用對象的緩存而不是創建對象。
            
            對生存時間越長,須要收集時間也越長,收集也會變慢。
            
            一次徹底的垃圾收集應該不超過3-5秒。
            
            若是系統花費不少時間收集垃圾,應該減小堆大小。
            
            通常來講,你使用物理內存的80%爲堆大小。
            
            對於1GB內存,單CPU的機器來講,以下的一組參考配置
            
            -Xms800m -Xmx800m  // 堆初始值和堆最大值同樣
            -Xmn200m           // 新域的內存
            -XX:PermSize=128m   // 永久域初始值
            -XX:MaxPermSize=128m // 永久域最大值
            -XX:NewSize=200m   // 新域的初始值
            -XX:MaxNewSize=200m // 新域最大值
            -XX:NewRatio=3        // 設置該值後可不設置NewSize
            -XX:SurvivorRatio=4 // 設置救助區域大小
            -XX:userParNewGC   // 可用來設置並行收集
            -XX:ParallelGCThreads   // 可用來增長並行度
            -XX:UseParallelGC  // 設置後可使用並行清除收集器
            -XX:UseAdaptiveSizePolicy // 上面一個聯合使用效果更好,利用它能夠自動優化新域大小和救助空間比值
            
        咱們常常遇到java.lang.OutOfMemoryError. Java heap space的錯誤
            
            根源是JVM虛擬機默認Heap大小是64MB,可經過設置最小值和最大值來解決
                
                (1) windows中更改系統環境變量
                    加上 JAVA_OPTS=-Xm800m -Xmx800m
                
                (2) tomcat的話,能夠在\bin\catalina.bat或catalina.sh加上
                    set JAVA_OPTS=-Xm800m -Xmx800m
        
        JVM調優實戰
            
            heap內存設置
            
                進入JAVA_HOME/demo/jfc/SwingSet2目錄
                    java -jar -Xmn4m -Xms16m -Xmx16m SwingSet2.jar
                        出現以下錯誤: Exception in thread "Image Fetcher 1" java.lang.OutOfMemoryError: Java heap space
                    
                    除了異常信息,會發現程序的響應速度變慢。
                    說明Heap size偏小,GC佔用了更多時間,應該分配到的執行時間較少。
                    
                    設置成以下,則安然無恙:
                        
                        java -jar -Xmn4m -Xms16m -Xmx32m SwingSet2.jar
                        
                    Heap最大不要超過可用物理內存的80%,通常要將-Xms和-Xmx選項設置爲相同,
                    而-Xmn爲1/4的-Xmx(heap最大值)
編程

相關文章
相關標籤/搜索