需要垃圾回收:
在程序执行的过程中,会产生一系列的对象(占用内存的代表),这些都会存储在内存中。一部分对象在生命周期结束后,依然会占用一部分内存。这些占用内存却没有再次使用的对象,我们称之为“垃圾”,而对“垃圾”占用的内存的回收,就是垃圾回收。
在没有垃圾回收机制的语言里,垃圾回收操作需要程序猿来完成,这常常会导致错误。
内存泄漏:忘记释放一部分内存,导致那一部分内存不可用,并且占用着总的内存空间,如果这种情况一直存在着,那么就可能导致内存空间被占满,系统崩溃。
垂直指针:忘记初始化指向释放了内存的指针(指向曾经存在的对象,但是对象已经不存在了),当再次调用指针的时候,指针指向了空内存,引起bug
释放错误的内存:人为的操作难免会发生错误,如果释放了错误的内存,也会导致程序发生莫名其妙的bug
- 垃圾收集器算法:
(1)标记–清除法(Mark–Sweep): 标记需要回收的对象,标记完成后再统一清除,将其内存空间释放
缺点:效率问题:清除和标记过程效率都不高;空间问题:会产生大量的不连续碎片内存。
2. 复制算法(copying):为解决效率问题,先将内存分为两个部分,两部分大小相等。对象分配时,只会在一个区进行分配。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
复制算法一般是使用在新生代中,因为新生代中的对象一般都是朝生夕死的,存活对象的数量并不多,这样使用复制算法进行拷贝时效率比较高。
优点:效率快;不会发生碎片化,移动堆顶指针,按顺序分配内存,实现简单,运行高效。
缺点:将内存空间缩小为原来一半;持续复制长生存期的对象则导致效率降低。
新生代的目标就是尽可能快速的手机掉那些生命周期短的对象。老年代的目标是存大对象或声明周期长的对象。
将新生代划分为Eden(伊甸园) 与2块Survivor Space(幸存者区,分别叫From Survivor Space 和 To Survivor Space) 。
然后在Eden –>Survivor Space 以及From Survivor Space 与To Survivor Space 之间实行Copying 算法。 不过jvm在应用复制算法时,并不是把内存按照1:1来划分的,这样太浪费内存空间了。
实际情况是,按照8:1:1来划分,每次GC,把Eden 和某一个 Survivor的存活对象,复制到另一个Survivor,然后把Eden和那个Survivor清空。这样,意味着每次GC后,可以有90%的内存会被利用,只有10%浪费。
如果万一存活对象放不下那个Survivor,会找老年代借一下,称为分配担保。
下图给出内存的具体划分:
具体工作流程如下:
在GC开始的前,对象只会存在于Eden区和From Survivor区,To Survivor区是空的。
紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置,默认15)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
对象年龄计算:没经过1次GC,年龄+1。
- 标记–整理法(Mark–Compact):
先标记,再把所有存活的对象向一端移动,然后直接清理端边界意外的内存。
4. 分代收集:
JVM内存分配策略:
(1) 对象优先分配在Eden区,当Eden区空间不足时,JVM会触发一次Minor GC(采用复制算法回收)。
(2) 大对象直接进入老年代,大对象指需要大量连续内存空间的对象。目的是避免在Eden区和Survivor区之间发生大量的内存拷贝。
(3)长期存活的对象进入老年代。JVM为每个对象定义了一个年龄计数器,对象经过一次Minor GC会进入Survivor区,之后每经过一次,对象年龄加1,达到阈值对象进入老年区。
(4)动态判断对象的年龄,如果survivor区相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象直接进入老年代。
(5)空间分配担保,每次进行Minor GC,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小,会进行一次Full GC ,如果小于,检查HandlePromotionFailure设置,如果为true 只进行Minor GC,否则进行Full GC。
JVM的平台无关性:javac编译成字节码文件,任何装了JVM的平台都可以直接运行