修改自:https://www.cnblogs.com/QG-whz/p/6557333.html
Java和C++的清理对象工作
《java编程思想》读到初始化与清理一章,文中提及java的finalize()方法,联想到了C++的析构函数。finalize()方法与析构函数存在天然差别,这种差别源于语言本身机制的不同。
1、Java和C++对无用对象的回收时机二者不同
在C++中,对象是可以在栈上分配的,也可以在堆上分配。在栈上分配的对象,也就是函数的局部变量,当超出块的"}"时,生命期便结束了。在堆上分配的对象,使用delete的时候,对象的生命期也就结束了。因此在C++中,对象的内存在哪个时刻被回收,是可以确定的(假设程序没有缺陷)。
Java秉承一切皆为对象的思想,对象仅能通过new来创建,因此java的对象是在堆上分配的内存。这些堆上的对象,如果没有作用了(无引用指向它),将等待垃圾回收器来回收其占用的内存。而垃圾回收期何时运行,无法提前预知,甚至有的时候只要程序没有濒临存储空间用完的那一刻,那么可能直到程序退出都没有进行垃圾回收,程序所占内存直接由操作系统来回收。所以在java中,对象的内存在哪个时刻回收,取决于垃圾回收器何时运行。
因此,C++与java中,对无用对象的回收时间是不同的。
2. Java的finalize()函数和C++的析构函数
一旦C++的对象要被回收了,在回收该对象之前对象的析构函数将被调用,析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存),然后释放对象占用的内存;而java中一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法, 并且在下一次垃圾回收动作发生时,才会真正的回收对象占用的内存(《java 编程思想》)。可见在java中,调用GC不等于真正地回收内存资源,而且在垃圾回收中对象存在状态的变化。
3. finalize()函数和析构函数的分别的作用
C++的析构函数用来做一些必要的工作,例如释放掉指针成员所指向的对象所占的内存,因为C++没有java的垃圾回收器,所有new出来的对象,都要显式地delete掉,避免内存泄漏。《Effective C++》中提及,基类需要将析构函数声明为virtual函数,这是为了可以通过子类对象指针正确地释放掉基类的资源。总的来说,在C++中,析构函数和资源的释放息息相关,能不能正确处理析构函数,关乎能否正确回收对象内存资源。
在java中,所有的对象,包括对象中包含的其他对象,它们所占的内存的回收都依靠垃圾回收器,因此不需要一个函数如C++析构函数那样来做必要的垃圾回收工作。当然存在本地方法时需要finalize()方法来清理本地对象。在《java编程思想》中提及,finalize()方法的一个作用是用来回收“本地方法”中的本地对象——C/C++代码所分配的内存,由于这部分的内存只能由delete/free来释放,因此可以放在finalize()方法中来做。在实际生产环境中,较少(或说基本没有)看到java类实现了finalize()方法。可以说java最大程度地弱化了内存管理对应用程序员的束缚,而c++则对此要求严格多了。