C语言申请内存、释放内存:malloc、free
C++申请内存、释放内存:new delete
java申请内存、释放内存:new 自动回收
自动内存回收简单,不易出错
手动回收存在得问题:忘记回收、多次回收
什么是垃圾
没有任何引用指向的一个对象或者多个对象(循环引用)
如何定位垃圾
1. 引用计数
记录有多少个引用指向某个对象,当引用数为0,这个对象就变成了垃圾,但这个方法不能解决循环引用的情况(因为循环引用内的对象引用数都为1)。
2. 根可达算法
到GC roots的引用数为0的对象。GC roots包括哪些对象呢(虚拟机栈中引用对象、本地方法栈中引用对象、方法区中常量引用对象,方法区中类静态属性引用的对象)
常见的垃圾回收策略
1. 标记清除法
首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。但存在标记清除后会产生大量不连续的碎片,从而导致空间问题。
2. 标记整理算法
比标记清理算法多了一个整理步骤,在回收之前让所有存活的对象向一端移动,直接清除掉端边界以外的内存。但这种办法每一次清除都要频繁的移动活动对象 效率低。
3. 复制算法(新生代算法)
复制算法是针对Java堆中的新生代内存垃圾回收所使用的回收策略,解决了”标记-清理”的效率问题。
那么什么是新生代内存呢?首先了解一下JVM内存:年轻代、老年代、永久代(推荐 转), jvm的新生代、老年代、永久代关系 以及 jvm中新生代和老年代的理解
从上面的资料中学习到:为了让内存回收更加高效,Sun JDK从1.2开始对堆采用了分代管理的方式。 JAVA程序中新建的对象大多数情况下都从新生代分配内存,而老年代呢,是用来存放新生代经过多次回收仍然存活的对象,例如缓存对象。新建的对象也有可能在老年代上直接分配内存,主要分为两种情况:1、大对象2、大的数组对象,且数组中无引用外部对象。
堆=新生代+老年代,不包括永久代(方法区)
永久代是Hotspot虚拟机特有的概念,是方法区的一种实现,别的JVM都没有这个东西。在Java 8中,永久代被彻底移除,取而代之的是另一块与堆不相连的本地内存——元空间。
永久代或者“Perm Gen”包含了JVM需要的应用元数据,这些元数据描述了在应用里使用的类和方法。注意,永久代不是Java堆内存的一部分。永久代存放JVM运行时使用的类。永久代同样包含了Java SE库的类和方法。永久代的对象在full GC时进行垃圾收集。
新生代的内存划分
新生代中98%的对象都是”朝生夕死”的,所以并不需要按照1 : 1的比例来划分内存空间,而是将内存(新生代内存)分为一块较大的Eden(伊甸园)空间和两块较小的Survivor(幸存者)空间,每次使用Eden和其中一块Survivor(两个Survivor区域一个称为From区,另一个称为To区域),比例通常为8:1:1,这个比例是可以修改的。
当进行垃圾回收时,将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。将此时在Survivor空间存活下来的对象的年龄设置为1,以后这些对象每在Survivor区熬过一次GC,它们的年龄就加1,当对象年龄达到某个年龄(默认值为15)时,就会把它们移到老年代中。
但是,有可能遇到当Survivor空间不够用时(回收后存活的对象超过10%时)的情况?
那会怎么办呢,这些对象则需要依赖其他内存(老年代)进行分配担保,进入老年代。
具体实现的复制算法流程如下:
- 当Eden区满的时候,会触发第一次Minor gc发生在新生代的垃圾回收成为Minor GC,Minor GC又称为新生代GC,Full GC(Major GC) 是发生在老年代的垃圾收集动作。把还活着的对象拷贝到Survivor From区;当Eden区再次触发Minor gc的时候,会扫描Eden区和From区域,对两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到To区域,并将Eden和From区域清空。
- 当后续Eden又发生Minor gc的时候,会 对Eden和To区域进行垃圾回收,存活的对象复制到From区域,并将Eden和To区域清空
- 部分对象会在From和To区域中复制来复制去,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认是15),最终如果还是存活,就存入到老年代。
复制算法将堆中可用的新生代内存按容量划分成大小相等的两块内存区域,每次只使用其中的一块区域。当其中一块内存区域需要进行垃圾回收时,会将此区域内还存活着的对象复制到另一块上面,然后再把此内存区域一次性清理掉。
这样做的好处是每次都是对整个新生代一半的内存区域进行内存回收,内存分配时也就不需要考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配即可。此算法实现简单,运行高效