1、堆與棧java
一、堆是全部對象共享的,存儲對象信息;算法
每個線程都有一個獨立的線程棧,棧存儲的是與當前線程相關的信息,包括局部變量、程序運行狀態、方法返回值等。服務器
二、堆中存儲的是對象,棧中存儲的是基本類型和堆中對象的引用。多線程
三、棧的大小配置 -Xss併發
四、在運行棧中,基本類型和引用的處理是同樣的,都是傳值。spa
五、能夠把一個對象看做爲一棵樹,對象的屬性若是仍是對象,則仍是一棵樹(非葉子節點),而基本類型則是葉子節點。操作系統
2、Java對象的大小線程
一、一個空的Object對象:對象
Object obj = new Object();遞歸
其所佔的空間爲: 8+4 =12 bytes 。其中8 bytes 是Java堆中對象的所需空間,4 bytes是棧中保存引用的所需空間
二、如下類
class NewObject
{
int count;
boolean flag;
Object obj;
}
其的對象 NewObject newObj = new NewObject();
newObj 所佔空間 8 + 4 +1 + 4 = 17 bytes.
其中8 bytes 爲 newObj 空對象大小,4 bytes爲 int 大小,1 byte爲 boolean 大小, 4 bytes爲 obj引用大小。
又由於Java對象內存分配以8的整數倍來分,故而對象的大小爲 24 bytes。
三、基本類型包裝類的大小至少是16bytes。
3、強引用、軟引用、弱引用
強引用:回收時候嚴格判斷
軟引用:內存緊張則回收,富餘則不回收
弱引用:每次GC一定回收,生命週期只存在於一個垃圾回收週期。
4、GC 基本策略
一、引用計算:沒法處理循環引用
二、標記-清除:從root節點開始標記全部引用對象,遍歷堆,清除未標記對象。缺點是須要暫停整個應用,產生內存碎片。
三、複製:將內存分爲兩塊,每次只使用其中一塊。回收時候複製到另外一塊。
四、標記整理:結合 「標記-清除」 和 「複製」, 不過不是複製到另外一塊內存,而是將對象放緊湊。
5、GC 分區策略
一、增量收集:實時垃圾回收。
二、分代收集:把對象分爲年輕代、年老代、持久代,對於不一樣生命週期對象採用不一樣算法。
6、GC 線程策略
一、串行收集:單線程處理,沒法使用多處理器的優點。須要暫停整個運行環境。
優勢:簡單,效率高。
缺點:只適合小型應用,數據量比較小。
配置:-XX:+UseSerialGC
二、並行收集:多線程處理,速度快,效率高。須要暫停整個運行環境。
優勢:吞吐量大,適用於數值計算、後臺處理。
缺點:響應時間長。
配置:XX:+UseParallelGC -XX:+UseParallelOldGC -XX:ParallelGCThreads=<N> -XX:MaxGCPauseMillis=<N> -XX:GCTimeRatio=<N>
三、併發收集:GC的同時不須要暫停整個運行環境。
優勢:響應時間快,適用於Web服務器等。
缺點:吞吐量沒那麼大。
配置:-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=<N>
7、分代回收
一、年輕代(Yong):一個Eden區,兩個Survivor區。Eden滿,放入一個Survivor。Survivor放入另外一個Survivor。另外一個Survivor滿,放入年老代。
二、年老代(Tenured):年輕代經歷N次GC後,對象放到年老區。放的是生命週期較長的數據。
三、持久代(Permanent):Java 類的 Class 信息,與GC關係不大。
Minor GC:只要Eden滿即觸發,速度很快。
Full GC:整個堆回收,速度慢。在年老代或者持久代滿的時候調用。
8、典型配置
java -Xmx3550m -Xms3550m -Xmn2g –Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0 XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-Xmx3550m: 最大可用內存
-Xms3550m:初始內存。此值能夠設置與-Xmx相同,以免每次垃圾回收完成後JVM從新分配內存。
-Xmn2g:年輕代大小
-Xss128k:每一個線程的棧大小
-XX:NewRatio=4: 年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)
-XX:SurvivorRatio=4:年輕代中Eden區與Survivor區的大小比值
-XX:MaxPermSize=16m: 持久代大小
-XX:MaxTenuringThreshold=0: 垃圾最大年齡。若是設置爲0的話,則年輕代對象不通過Survivor區,直接進入年老代
-XX:+UseParallelGC:選擇並行收集器
-XX:ParallelGCThreads=20: 並行收集器的線程數
-XX:+UseParallelOldGC: 年老代垃圾收集方式爲並行收集
-XX:MaxGCPauseMillis=100:每次年輕代垃圾回收的最長時間
-XX:+UseAdaptiveSizePolicy:自動選擇年輕代區大小和相應的Survivor區比例
-XX:+UseConcMarkSweepGC:設置年老代爲併發收集
-XX:+UseParNewGC: 設置年輕代爲並行收集
-XX:CMSFullGCsBeforeCompaction=5:運行多少次GC之後對內存空間進行壓縮、整理。
-XX:+UseCMSCompactAtFullCollection:打開對年老代的壓縮
9、調優總結
一、吞吐量優先:
年輕代大、並行垃圾收集、年老代小。
儘量回收掉大部分短時間對象,減小中期的對象,而年老代盡存放長期存活對象。
二、響應時間優先:
年輕代大、併發垃圾回收、年老代適中。
年老代使用併發收集器,因此其大小須要當心設置,通常要考慮併發會話率和會話持續時間等一些參數。若是堆設置小了,能夠會形成內存碎片、高回收頻率以及應用暫停而使用傳統的標記清除方式;若是堆大了,則須要較長的收集時間。
10、年老代碎片問題:
解決:
一、-XX:+UseCMSCompactAtFullCollection:使用併發收集器時,開啓對年老代的壓縮。
二、-XX:CMSFullGCsBeforeCompaction=0:上面配置開啓的狀況下,這裏設置多少次Full GC後,對年老代進行壓縮
11、常見JVM 異常
一、java.lang.OutOfMemoryError: Java heap space
緣由:典型的內存泄露,全部堆空間都被沒法回收的垃圾對象佔滿。
解決:找到泄露點,通常是集合對象引用。
二、java.lang.OutOfMemoryError: PermGen space
緣由:持久代佔滿,沒法爲新的class分配存儲空間而引起的異常。主要緣由是大量動態反射生成的類不斷被加載。不一樣的classloader 即使使用了相同的類,可是都會對其進行加載,至關於有一個class會被N個classloader加載N次。
解決:-XX:MaxPermSize=16m
三、java.lang.StackOverflowError
緣由:遞歸沒有返回,或者循環調用。
解決:修正代碼
四、Fatal: Stack size too small
緣由:線程空間大小被限制
解決:增大線程棧,-Xss2m。也多是代碼內存泄露。
五、java.lang.OutOfMemoryError: unable to create new native thread
緣由:操做系統沒有足夠資源產生這個線程
解決:配置系統,如ulimit。減少線程棧大小,-Xss。