JVM堆是JAVA程序运行时对象的存储位置,其存储方式和垃圾收集机制是我们调优的一大关键。
堆的构成
堆从内存回收的角度看,由于现在收集器基本都采用分代收集算法,所以堆可细分为新生代和老年代,新生代占1/3,老年代占2/3.
新生代又被分为Eden和Surviver,Surviver被分为from和to两个部分。也就是新生代一共有三个部分,内存占比默认为8:1:1,这个占比可以调节。
进行划分的目的是为了更好的进行内存回收。
新生代与老年代的存放
上面说了新生代细分成了三部分,Eden和属于Survivor的两个部分。当一个新的对象生成时,就会放入新生代区(太大的对象也会直接放入老年代)。
JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。并且新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。
老年代则是在GC之后年龄到15的对象则存入老年代。
堆的垃圾回收
java堆是GC垃圾回收的主要区域。 GC分为两种: Minor GC、Full GC(也叫做Major GC).
Minor GC
Minor GC是发生在新生代中的垃圾收集动作, 所采用的是复制算法。
Minor GC是字节码执行引擎开启的一个垃圾回收线程。
过程:将“GCRoots”对象为起点做可达性分析,从这些节点开始向下搜索引用的对象,找到的对象标记为非垃圾对象,其余未标记的对象都是垃圾对象。
然后垃圾对象被清除,留下的对象被放入Survivor任意一个区里面(与初始相反的区),并且分代年龄加一。
直到年龄到15(默认)后,放入老年区。
ps:分代年龄和对象一起放在堆里
就像数据包有帧头一样,JAVA的对象也有对象头,对对象的描述数据就存放在这。
Full GC
Full GC 基本都是整个堆空间及持久代发生了垃圾回收,所采用的是标记-清除算法。
老年代里面的对象几乎都是在 Survivor 区域中熬过来的,它们被调用的很频繁,不怎么需要回收。因此,Full GC 发生的次数不会有 Minor GC 那么频繁,并且做一次 Full GC 要比进行一次 Minor GC 的时间更长,一般是Minor GC的 10倍以上。
另外,标记-清除算法收集垃圾的时候会产生许多的内存碎片 ( 即不连续的内存空间 ),此后需要为较大的对象分配内存空间时,若无法找到足够的连续的内存空间,就会提前触发一次 GC 的收集动作。
这里提一下标记-整理算法,这个算法和标记-清除类似,但会对内存空间进行整理,故不会有太多的内存碎片。
以上为笔者参考资料结合自己理解所写,若有错误欢迎指出,望共同进步,peace~