java回收机制劣势_Java垃圾回收机制浅谈

关于堆栈与栈

在了解Java的垃圾回收机制前,我认为有必要简单地了解JVM的一点小知识:一般程序在启动时,JVM会将内存分成几个部分:数据区、堆栈(stack)、堆(heap)等等,而在此处我们重点了解堆栈(stack)和堆(heap),一般我们可以认为JVM内存可分成栈内存和堆内存两种。

堆(heap):是一个运行时的数据区,类的对象就是存储在此,即那些通过new、newarray等指令所建立起来的对象所占用的内存是由堆内存分配而来,由于是在运行时动态分配内存的,所以存取速度相对比较慢。

栈(stack): 是一个静态数据区,主要用于存放一些基本数据类型(int,short,long,byte,float,double,boolean,char)和对象句柄(即对象引用),由于栈中的数据在编译器就可确定,所以存取速度比堆要快,仅次于寄存器,栈数据可以共享。

举个例子:

String a = new String("zbx"); 该式中a为对象句柄,存放于堆栈中,而通过new关键字所创建的对象则存放于堆中。

什么是垃圾回收

众所周知,Java中提供了GC(Garbage Collection)机制,即垃圾回收机制。那么究竟何为垃圾回收呢?在Java中,没有被对象句柄所引用的对象和长时间没有被使用过的对象均可被视为"垃圾",如在上述代码下再加上一句:

String a = new String("zbx");

a = null; 则此时右边的对象便没有对象句柄指向它,理所当然它便成了"垃圾",而垃圾会由Java所提供的

垃圾回收器

自动回收,这便是所谓的垃圾回收。同时,我们可以发现,垃圾回收只存在于堆空间中,而栈中不存在垃圾回收。

垃圾回收的意义

在c/c++中,程序员要想使用内存,必须自己手动调用malloc()函数来分配存储空间,而使用完后必须手动通过free()函数来释放空间,然而却有很多粗心的程序员忽略了这一重要步骤,导致这块被分配的空间站着茅坑不拉屎,自己不再使用,也不让别人用,当存在太多这样的"无用空间"时,便会出现我们常说的内存泄漏的现象。

在这种情况下,垃圾回收的作用则显得非常重要,因为它不需要程序员手动释放所占用的"无用"内存,它会自动检测内存中存在哪些不再使用的内存,并采取回收的措施,我认为这样的好处就是提高了编程的效率,降低了编程的负担。但任何事物都必有两面性,垃圾回收也不例外,因为该过程是自动执行的,所以会有一定的系统开销,会在一定的程度上影响性能。

怎么进行垃圾回收

finalize方法

(1)基本描述与作用

在java在进行垃圾回收前,会调用对象的finalize方法,但是真正的垃圾回收则是在下一次垃圾回收动作发生时才进行的。这句话听着有点怪怪的,那么finalize方法的作用是什么呢?finalize()的实际作用是在垃圾回收器回收垃圾并释放内存前做一些重要的"清理工作"。如jdk1.6文档中的例子所言,表示输入/输出连接的对象的 finalize 方法可执行显式 I/O 事务,以便在永久丢弃对象之前中断连接。

(2)与析构函数的区别

有了上述对finalize方法的基本描述之后,接触过C++的朋友想必会认为finalize方法其实就是C++中的析构函数(C++中销毁对象必须使用到的函数,用于销毁时的一些善后工作),但是这不对C,C++中,调用了析构函数后,对象一定会被销毁,而Java中调用了finalize方法,垃圾却不一定会被回收。因此我们需要牢记:对象可能不被垃圾回收。

(3)何时进行调用

根据jdk1.6文档描述,对于任何给定对象,Java 虚拟机最多只调用一次finalize方法。并且调用finalize方法的工作只需要交给jvm进行就可以了,我们极少情况下需要手动调用该方法,一般情况下我们不会显示地调用它,因为这样可能会造成二次调用的情况,当在第二次调用该方法时,如果试图释放已经释放的内存时,会抛出异常,"垃圾"回收工作则无法顺利进行。既然如此,那么jvm会在何时调用finalize方法呢?一般而言,只要程序没有在濒临内存空间不足的时候,jvm始终不会主动进行垃圾回收,也就是说,只有在程序内存快用完的那一刻,jvm才会主动去搜索已经不再使用的"垃圾",并及时对其进行清理工作。

class Test{

private String name;

public Test(String name){

this.name = name;

}

protected void finalize(){

System.out.println("调用了"+name+"的finalize方法");

//super.finalize();

}

}

public class GCTest{

public static void main(String[] args){

for(int i=0;i<30000;i++){

Test test = new Test(i+"");

}

}

}

如上述代码所示,当不断地创建新对象时,内存资源不断减少,当内存将近殆尽的时候,finalize方法得到了调用。那么有没有更快地调用finalize方法的方法呢?答:有

gc方法

在java中,提供了System.gc()与Runtime.getRuntime().gc()两种方法,他们的作用实际上是一样的,都是建议jvm进行垃圾回收,注意这里加黑了"建议"两字,意思就是说,该方法仅仅是提议jvm进行垃圾回收,而具体什么时候进行垃圾回收确是不确定的,更形象一点的来说,你对jvm说,是时候倒垃圾了,而jvm只回答到,我知道了,具体它什么时候倒垃圾,嘿嘿.看它心情了。不过一般只要你调用了System.gc();(一般我使用这个),jvm都会很快响应,并调用finalize方法。

class Test{

private String name;

public Test(String name){

this.name = name;

}

protected void finalize(){

System.out.println("调用了"+name+"的finalize方法");

//super.finalize();

}

}

public class GCTest{

public static void main(String[] args){

Test test = new Test("zbx");

test = null; //让原本的对象无引用指向,变成垃圾,符合垃圾回收的条件

System.gc(); //建议jvm进行垃圾回收

}

}

运行上述程序,将输出:调用了zbx的finlize方法。

持续更新,如有错漏之处,欢迎指正,希望能够相互交流,共同进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值