内存中的区域是如何划分的,对象的引用在哪个区域?
Java虚拟机将内存分为两个部分,一个线程共享的,一个线程私有的。线程共享的有方法区和堆,线程私有的有栈、本地方法栈和程序计数器。
堆用来存放对象实例,栈用来存放形参或局部变量。
什么是垃圾回收机制
垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存。
内存泄露是指该内存空间使用完毕之后未回收,内存泄露过多会导致内存溢出,导致应用程序所占内存超出系统限制,最终被系统杀掉。
什么是垃圾
这里的垃圾是指无用的对象或其它数据等已经不被需要,但却无法被GC所释放。
GC所使用的两种判断垃圾的算法
1.引用计数法
A a = new A();
a = null;
引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象实例都有一个引用计数。当一个对象被创建时,且将该对象实例分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象实例的计数器+1),但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数器减1。任何引用计数器为0的对象实例可以被当作垃圾收集。当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数器减1。
引用计数法无法检测出循环引用,两个对象互相引用的情况无法被检测出。
2.可达性算法(根搜索算法)
从根引用节点开始检索这个节点引用的节点,当所有的被引用节点都被找到后,剩余的节点则被认为是没有被引用的节点,需要被回收。
java中作为GC的根节点有
- 虚拟机栈中引用的对象,本地变量
- 方法区中静态属性引用的对象
- 方法区中常量引用的对象
- Native对象
GC所使用的几种回收的算法
1.标记清除算法
1234 2 3
从根集合扫描,将存活的对象进行标记,标记完毕后再扫描一遍,对未进行标记的对象进行回收。标识清除算法不需要进行对象的移动,仅对不存活的对象进行处理,容易造成内存碎片。适用于存活率高的情况。
2.复制算法
将可用内存空间分为两个部分,开始只使用其中的一半,在这一半用完后再将存活的对象复制到另外一块上。适用于存活率低的情况,避免了内存碎片的情况。
3.标记整理算法
同标记清除算法一样进行标记,但在清除时将后面的对象在内存空间上向左移动,相比标记清除来说成本更高,但没有内存碎片的问题
4.分代收集算法
对对象进行分代,不同代的对象采取不同的回收算法,提高效率。
年轻代,新生成的对象都归为年轻代,年轻代在存放满和其它情况都会触发Minor GC
老年代,大对象直接进入老年代,年轻代经历几次垃圾回收后仍然存活的对象也进入老年代。老年代存放满后触发Major GC(Full GC)
持久代,用于存放静态文件,Java类、方法等。基本不被回收。
四种引用
强引用,一般引用,将对象指给变量就属于这种。
软引用,有用但并非必要的对象,在系统即将要发生内存溢出之前,会将这些对象列入回收范围再进行一次回收。
弱引用,比软引用更弱一些,在内存回收时也会被列入内存回收的范围。
虚引用,最弱的引用关系。无法通过虚引用获取到对象实例,虚引用的目的为希望能在这个对象被回收的时候收到一个系统通知。