Chapter 3:垃圾收集器和内存分配策略
每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的....
判断对象是否存活的算法:
1、引用计数算法:
对象中维持一个计数器,当有一个引用指向它,计数器加1;当引用失效的时候,计数器减1;当计数器为0的时候,该对象就可以被jvm回收。但Java中并没有采用这种算法:
public class Client{
public static void main(String[] args) {
O a = new O();
O b = new O();
a.o = b;
b.o = a;
a = null;
b = null;
}
}
class O{
public Object o;
}
上述例子中,对象a和对象b肯定会被回收的,但是他们之间相互引用。堆内存中a的区域中含有对b的引用,b的区域中含有对a的引用...按照引用计数算法是不会被回收的...所以Java并不是采用引用计数算法...
2、根搜索算法:
当从任何GC Roots开始都到达不了某个对象的时候,这个对象是不可用的,也是被回收的..
GC Roots包括:虚拟机栈中的引用的对象;本地方法栈中的引用的对象;类静态属性的引用的对象;常量引用的对象。。。根据这个来看,就是说从任何一个引用都达不到这个对象,那么这个对象就可以被回收了....
Java中的引用:
强引用:是指普遍存在的引用,类似于Object a = new Object()这种。垃圾回收期永远不会回收强引用
软引用:如果当前内存不够用,垃圾回收期会回收掉软引用指向的对象;
弱引用:不管内存够不够,在一次垃圾回收的时候,弱引用指向的对象总是要被回收;
虚引用:最弱的一个引用....
Finalize函数:
public class Gc {
public static Object s = null;
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
super.finalize();
System.out.println("Finalize Run!");
Gc.s = this;
}
public static void main(String[] args)throws Exception {
Gc.s = null;
Gc.s = new Gc();
Gc.s = null;
System.gc();
Thread.sleep(500);
if(Gc.s == null)
System.out.println("DEAD");
else
System.out.println("ALIVE");
}
}
GC在回收某个对象的时候会调用该对象的Finalize函数,如果在Finalize函数中对该对象添加了一个引用,那么该对象就可以免于回收。
Finalize函数只能被调用一次
GC分代收集:
根据对象的存活周期不同,将Java堆分成新生代和老年代:
在新生代中,每次垃圾收集都会有大批对象死亡,所以采取复制算法。将内存分成一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Sruvivor空间。回收时,将Eden和Survivor中还存活的对象一次性拷贝到另一块Survivor空间中,最后清理掉刚才使用的Eden空间和Sruvivor空间。
在老年代中,每次垃圾收集都会有大批对象存活,所以采用标记-清理算法或者标记-整理算法。
this关键字:
通过Javac编译器在编译的时候把对this关键字的访问转变成对一个普通方法参数的访问,然后在虚拟机调用实例方法时自动传入此参数即可。因此在实例方法的局部变量表中至少会存在一个指向当前对象实例的局部变量。