https://www.cnblogs.com/andy-zhou/p/5327288.html
栈是运行时的单位,而堆是存储的单位。
栈代表了处理逻辑,而堆代表了数据
一个空Object对象的大小是8byte
Object ob = new Object();
这样在程序中完成了一个Java对象的生命,但是它所占的空间为:4byte+8byte。4byte是上面部分所说的Java栈中保存引用的所需要的空间。而那8byte则是Java堆中对象的信息。
Java对象大小是8的整数倍因此一个基本类型包装类的大小至少是16byte。
按照基本回收策略分
引用计数(Reference Counting):
标记-清除(Mark-Sweep):
复制(Copying):
标记-整理(Mark-Compact):此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。
分代收集(Generational Collecting):基于对对象生命周期分析后得出的垃圾回收算法。
把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。
现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。
以栈或寄存器中的引用为起点,我们可以找到堆中的对象,又从这些对象找到对堆中其他对象的引用,
这种引用逐步扩展,最终以null引用或者基本类型结束,
这样就形成了一颗以Java栈中引用所对应的对象为根节点的一颗对象树,如果栈中有多个引用,则最终会形成多颗对象树。
虚拟机中的共划分为三个代:年轻代(Young Generation)、年老点(Old Generation)和持久代(Permanent Generation)。
其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大。年轻代和年老代的划分是对垃圾收集影响比较大的。
年轻代:
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。
年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。
当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,
此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,
从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。
需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,
和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。
而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),
这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。
年老代:
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中
什么情况下触发垃圾回收
Scavenge GC
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC
Full GC
对整个堆进行整理,包括Young、Tenured和Perm、在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节
年老代(Tenured)被写满
· 持久代(Perm)被写满
· System.gc()被显示调用
·上一次GC之后Heap的各域分配策略动态变化
最大垃圾回收暂停:指定垃圾回收时的最长暂停时间,通过-XX:MaxGCPauseMillis=指定。为毫秒.
如果指定了此值的话,堆大小和垃圾回收相关参数会进行调整以达到指定值。设定此值可能会减少应用的吞吐量。
吞吐量:吞吐量为垃圾回收时间与非垃圾回收时间的比值,通过-XX:GCTimeRatio=
来设定,公式为1/(1+N)。例如,-XX:GCTimeRatio=19时,表示5%的时间用于垃圾回收。默认情况为99,即>1%的时间用于垃圾回收。
并发收集器主要减少年老代的暂停时间,他在应用不停止的情况下使用独立的垃圾回收线程,
在一个N个处理器的系统上,并发收集部分使用K/N个可用处理器进行回收,一般情况下1<=K<=N/4。
浮动垃圾:由于在应用运行的同时进行垃圾回收,所以有些垃圾可能在垃圾回收进行完成时产生,
这样就造成了“Floating Garbage”,这些垃圾需要在下次垃圾回收周期时才能回收掉。
所以,并发收集器一般需要20%的预留空间用于这些浮动垃圾。
调优总结
年轻代大小选择
响应时间优先的应用、吞吐量优先的应用
年老代大小选择
网上一个很形象的例子描述对象在JVM堆内存中的生命周期:
我是一个普通的java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,
我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“To”区,
自从去了Survivor区,我就开始漂泊了,因为Survivor的两个区总是交换名字,所以我总是搬家,
搬到To Survivor居住,搬来搬去,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。
于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。
在年老代里,我生活了20年(每次GC加一岁),然后被回收。
jvisualvm工具使用
http://www.cnblogs.com/wade-xu/p/4369094.html
准备工作
jdkのbinフォールダのjvisualvm を起動
StringBuffer类型的 全局变量 tempOOM 占用内存特别大, 注意局部变量是无法通过 堆dump来得到分析结果的。
另外,对于“堆 dump”来说,在远程监控jvm的时候,VisualVM是没有这个功能的,只有本地监控的时候才有。