Java学习笔记之对象清除、垃圾收集


(最近刚来到简书平台,以前在CSDN上写的一些东西,也在逐渐的移到这儿来,有些篇幅是很早的时候写下的,因此可能会看到一些内容杂乱的文章,对此深感抱歉,以下为正文)


正文

本篇来聊聊java中的内存回收机制。

如果有C++编程经验的朋友,肯定知道在C++中如果创建了一个对象,当不再使用的时候,需要手动调用delete方法来进行销毁。那么在Java中我们为什么可以自由的创建对象而不用去考虑如何销毁它们呢(其实也是要考虑的,只是平常忽略了它)?因为Java提供了一套完整的垃圾回收机制(gc)。它会自动扫描内存中我们所创建过且不再使用的对象,进行自动销毁。听上去是不是很高端呢~

虽然听上去很不错并且它也确实能帮助我们自动销毁不用的对象,但它并非完美,因为我们在程序运行的时候,我们并不知道gc什么时候会来销毁那些我们所不再使用的对象,gc一般只有在资源开始紧张的时候,才会以独立的优先级的方式运行。事实上如果说gc足够完美的话,所谓的内存溢出是不是就很少出现了呢?然而现实中还是会出现内存溢出的情况的,这也从另一方面说明了gc的工作流程是不能被保证的。

下面我们要说说几个相关的方法,finalize(),System.gc(),System.runFinalization()以及System.runFinalizersOnExit(true)。

finalize():
finalize方法是定义在Object对象中的:

protected void finalize() throws Throwable { }

该方法只有在gc开始着手清理该对象时才会执行,suoyiJVM并不是必定会执行该方法的,比如你的程序在退出前都没有释放过该资源,那么该方法就不会执行。所以如果你重写了该方法,并在其中写了一定的操作,那么它是不能被保证一定执行的。

System.gc():
该方法有时被人称作强制调用系统的gc,然而这是不准确的,该方法只是建议gc进行一次回收,然而对于它是否能被执行,这是不受保障的。

System.runFinalization():
该方法是用来强制调用已经失去引用的对象finalize方法。

System.runFinalizersOnExit(boolean value):
该方法用于在程序结束后进行垃圾回收。该方法如今已被废弃,因为其存在安全性问题,因为它可能导致仍在活动的对象调用finalizers,当有线程并发操作这些对象的时候就会出现一些奇怪的行为和死锁。

下面通过一个小例子来加深理解:

package test;
 
 
public class GCTest {
    public static void main(String[] args) {
        //当运行时没传入参数提醒传入参数,before/after/others
        if (args.length == 0) {
            System.err.println("Usage: \n" + "java Garbage before\n or:\n"
                    + "java Garbage after");
            return;
        }
        
        //当finishCreate标记不为true时,持续创建Demo对象和String对象,String对象是为了加大内存消耗,来吸引gc的关注
        while (!Demo.finishCreate) {
                new Demo();
                new String("To take up space");
                
        }
        System.out.println("After all Demos have been created:\n"
                + "total created = " + Demo.createdNum + ", total finalized = "
                + Demo.finalizedNum);
        
        //如果传入的参数为before,则先后执行System.gc()和System.runFinalization();
        if (args[0].equals("before")) {
            System.out.println("gc():");
            System.gc();
            System.out.println("runFinalization():");
            System.runFinalization();
        }
        System.out.println("bye!");
        //如果传入的参数为after,则调用System.runFinalizersOnExit(true),该方法已被废弃,因为存在安全性
        if (args[0].equals("after"))
            System.runFinalizersOnExit(true);
    }
}
 
 
class Demo {
    // 判断当前内中gc是否运行
    static boolean gcrun = false;
    // 用于控制是否继续生成对象的开关
    static boolean finishCreate = false;
    // 用来记录对象创建的数量
    static int createdNum;
    // 用来记录对象被销毁的数量
    static int finalizedNum;
    
    static boolean tempFlag;
    // 用来区分当前对象的标记
    int id;
 
 
    // 无参构造函数
    public Demo() {
        // 每创建一个对象,createNum+1,并将其赋值给当前对象id
        id = ++createdNum;
        if (createdNum == 50) {
            System.out.println("the fiftieth Demo has been created");
        }
    }
 
 
    @Override
    protected void finalize() throws Throwable {
        //当第一次执行finalize的时候,表示gc开始自动销毁对象了
        if (!gcrun) {
            gcrun = true;
            System.out.println("Gabage Collection begins running after "
                    + createdNum + "demo objects have been created");
        }
        //当销毁的对象id>=50时,将finishCreate标记置为true,停止创建更多的对象
        if (id >= 50 && !tempFlag) {
            tempFlag = true;
            finishCreate = true;
            System.out
                    .println("the fiftieth demo begins to finalize and stop creating more demos");
        }
        //没执行一次finalize方法,finalizeNum都加1
        finalizedNum++;
//      System.out.println(finalizedNum+"===="+createdNum);
        //当finalizeNum >= createNum,表示所有对象都被清除
        if (finalizedNum >= createdNum) {
            System.out.println("all gabage have benn collected");
        }
    }
 
 
}

运行上述代码,传入不同的参数,可以进行不同的操作,Eclipse中带参的运行方法为右键Run As > Run Configurations... > Arguments 填入参数:


Eclipse带参数的运行方法

下面为几种运行结果:

1.传入参数before运行:


控制台打印

打开Demo类finalize中的打印语句可以看到如下打印:


控制台打印

第一种执行的是System.gc()和System.runFinalization()方法,从最后的输出可以看出,并没有完全的销毁对象,程序就结束了,这再一次证明了java垃圾回收机制的不确定性。

2.传入参数after运行:


控制台打印

打开Demo类finalize中的打印语句可以看到如下打印:


控制台打印

通过以上打印可以看出,所有的对象都被清理了,但明显感觉到程序的效率变慢了。

3.传入参数test运行:


控制台打印

打开Demo类finalize中的打印语句可以看到如下打印:


控制台打印

传入test,表示任由java的垃圾回收机制运行,不做人为干涉,可以看出,其活动性比较不频繁,因为此时内存还比较充足。

一般情况下,我们并不需要自己去提醒gc进行内存回收,当我们使用完一个对象后,推荐是将它置为null,由gc自动回收。

以上为本篇的全部内容。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,423评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,147评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,019评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,443评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,535评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,798评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,941评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,704评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,152评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,494评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,629评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,295评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,901评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,978评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,333评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,499评论 2 348

推荐阅读更多精彩内容