第5章.初始化与清理
1. 涉及基本类型的参数传递
如果传入的数据类型小于方法中声明的参数类型,实际数据类型就会提升。char型不同,如果无法找到恰好接受char参数的方法就会直接提升至int型。
如果大于就要主动执行窄化转化,否则编译器会报错。
2. this、constructor AND static
编译器实际上把"所操纵对象的引用"作为第一个参数传给方法,即Class.method(a,1);这是内部的表示形式,我们不能这样写。
除了构造器,不能在其他任何方法中调用构造器(this()方法),不能调用超过一个构造器,且必须置于最起始处,即方法的第一行。
static方法不是通过向对象发送消息方式实现的。
3. finalize()
垃圾回收器只会释放经new分配的内存。有时可能不通过new获得内存,为此,java允许在类中定义finalize()方法。原理是:一旦垃圾回收器准备好释放对象占用的内存空间时,首先调用对象的finalize()方法,并在下次垃圾回收发生时才会真正回收对象占用的内存。这和C++当中的析构函数是不同的。
注意:
- 对象可能不被垃圾回收回;
- 垃圾回收不等于“析构”;
- 垃圾回收只和内存有关。
只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放,使用垃圾回收器的唯一原因是为了回收程序不再使用的内存,所以对于任何与垃圾回收有关的行为来说,它们也必须同内存及其回收有关。
下面是finalize()一种可能的使用的方式:
class Book{
boolean checkedOut = false;
Book(boolean checkOut){
checkedOut = checkOut;
}
void checkIn(){
checkedOut = false;
}
protected void finalize(){
if(checkedOut)
System.out.println("Error:checked out");
//Normally, you`ll also do this:
//super.finalize();
//Call the base-class version
}
}
public class TerminationCondition{
public static void main(String[] args){
Book novel = new Book(true);
//Proper cleanup;
novel.checkIn;
//Drop the reference,forget to clean up;
new Book(true);
//Force garbage collection & finalization;
System.gc();
}
}
/*Output:
Error:checked out
*/
本例的终结条件是:所有Book都应该被签入(check in)。但在main方法中由于一些原因有一本书未被签入,如果没有finalize()来验证终结条件将很难发现这种缺陷。
4. 垃圾回收器如何工作?
有关效率
垃圾回收器对提高对象的创建速度有显著效果,有时可以同其他语言从栈上分配的方式媲美。C++中堆是一个无序的块,对象可以被销毁,但内存必须被重新利用。Java中更像一条带子,每分配一个新对象“指针”就向前移动一格。实际当中在登记方面还有少量开销,但总体来说是非常快的!
但也并非完全像是在栈中工作那样,否则会导致频道的内存页面调度。垃圾回收器的介入,在工作时一面回收空间,一面对对象重新排列,这就实现了一种高速的、有无限空间可供分配的模型。
引用计数 是一种简单但速度很慢的回收技术,缺陷在于,经常会在计数为0立即回收内存,而且对象之间循环引用,可能会出现“对象应该被回收,但引用计数不为零”的情况,垃圾回收器定位这种交互引用对象组所需的工作量极大。因此,从未被应用于任何一种JVM实现中。
更快的模式中,依据这样的思想:对任何“活”的对象,一定能最终追溯到其存活在堆或静态存储区中的引用,这个引用链条可能穿越数个对象层次 。由此,可以从栈和静态存储区开始遍历所有引用,每个引用全部追溯到底,直到所有引用形成的网络被全部访问为止,所访问过的对象必须是“活”的。这解决了“交互引用对象组”的问题。这种方式下JVM采用一种自适应的垃圾回收技术。如何处理找到的存活对象JVM有不同的实现:
- 停止-复制(stop-and-copy):先暂停程序,然后将所有存活对象从当前堆复制到另一个堆,没被复制的全是垃圾。复制到新堆的对象一个挨一个保持紧凑排列,然后就可以按前述方法简单、直接分配内存地址了。复制后所有引用必须修正,栈和静态存储区的引用可以直接修正,其他指向对象的引用在遍历过程中才能被修复。缺点在于,效率低,需要维护比实际多一倍的空间。而且程序稳定后垃圾产生很少,这种做法此时就会很浪费。一些JVM会进行检查,没有垃圾产生就转换到另一种工作模式(即“自适应”)。
- 标记-清扫(mark-and-sweep):这种模式同样从遍历引用开始,每找到一个活的对象就投一个标记,这个过程不会释放任何对象,只有全部标记工作完成时清理工作才开始。没有标记的对象被释放,没有复制动作发生,但剩下的空间是不连续的。如果垃圾回收器希望得到连续空间就需要重新整理。这种方式在只产生少量垃圾时是很快的。
以上两种方式都要程序暂停,因此都不属于后台回收模式。
JVM中还采用了很多附加技术用以提升速度。尤其是与加载器有关的,被称为“即时‘’(just-in-time,JIT)编译器的技术。
浙公网安备 33010602011771号