初始化和清理,理论的认识垃圾回收

第四章:初始化和清理

首先是构造函数,之前有学:构造函数的重载方法是通过参数而非返回类型进行区分的,当用户自定义了构造函数,系统不会再自动定义构造函数。此处对于this这个关键字有了一定的了解:this是对当前对象的引用,它就是个引用。它能用在某个对象的方法中,表示该对象,this在构造函数中使用相当于调用一个符合参数列表的构造函数staitc方法中不存在

this,所以它不能调用非静态的方法或者变量,因为没有对应的引用去指向这些方法和变量。

测试如下:

package com.cedric.thinkingInJava.test;

//?new 返回一个对象的引用,怎么看new的底层运行机制

class Chapter4 {

    public Chapter4() {

       this(5);

       System.out.println("empty");

    }

    public Chapter4(int i) {

       System.out.println(i);

    }

    int i = 0;

    Chapter4 getThis() {

       i++;

       return this;

    }

}

 

public class Chapter4Test {

    public static void main(String[] args) {

       Chapter4 c1 = null;

       c1 = new Chapter4();

       System.out.println(c1.getThis().i);

    }

}

运行结果为:

5

empty

1

其次是清理,理论性的认识了java一直吹捧的垃圾回收功能。除了垃圾回收,另一个清理方式是“终结”操作(finalize())。终结操作存在的原因是:1)对象可能不被垃圾回收2)垃圾回收并不等于“析构”,即垃圾回收只有在JVM内存将要耗尽时才执行,如果需要进行对象的消除,必须自己动手执行清理工作。3)垃圾回收只与内存有关(java中存在一些并非属于java的代码,可能会用到Cmalloc()等,所以finalize()不适合普通的清理)。这里主要是对垃圾回收做了一个了解:

首先明确:只有当JVM面临内存耗尽时才会去执行“垃圾回收”或者“终结”操作。

对象存在于内存中,要消除不用的对象就是对内存的一个操作。JVM中的堆像是一个传送带,每分配一个对象就向前移动一格,“对指针”每次只要指向未分配的区域就行,这样效率会极高。以上只是理想状态,因为要做到堆能够像传送带一样,把已分配的和未分配的完全整理好需要极大的内存页面调度。

为了解决以上问题,就引入了垃圾回收器,它能够在一面回收空间的同时一面使堆中的对象紧凑的排列。

垃圾回收器(GC):简单的理解是每个对象都被分配一个“引用计数”,当给对象添加一个引用时,对应的对象中的“引用计数”就加1,反之就减1,如果“引用计数”为0时,则认为对象不再被使用,将视为垃圾进行释放。这是一个简单的理解,但实际并不会运用该技术,因为当对象之间存在嵌套时,会出现对象不再使用,但是“引用计数”不为0的情况

Dog dog=new Dog()

Tail tail=new Tail();

dog.tail=tail;

Tail.dog=dog;

要消除dog必须先消除tail,但是要消除tail必须先消除dog

实际并不会运用“引用计数”的方式,而是做以下操作:从堆栈中找到所有的引用,对于每一个引用,追踪它引用的对象,然后追踪这个对象的所有引用,如此反复,直到所有引用全部被访问为止,这就解决了上述交互引用的问题。

GC找到对象,并确认它是“活”的,那么会用一种叫“停止-复制”的方法来处理对象:先暂停程序,然后将活的对象全部整齐的复制到另一个堆中,没有复制的就被视为垃圾,被复制的则整齐的排列在了一起。这种方法需要所有引用在复制时都需要进行修正,而且需要两个堆,所以效率会较低。当垃圾很少或者没有的时候,这种方式就不实用了,另一种名为“标记--清扫”的方法则会被使用。它的工作原理就是从堆栈中遍历所有的引用,对每个引用,如果存在活的对象就进行标记,最后没有被标记的就视为垃圾处理,这样会导致堆控件的不连续,但是在没有垃圾或者少量垃圾的前提下是一种高效的方式。两种方式会在JVM中“智能”的切换使用。

最后是初始化。对于以下这个类

class VariableInit{

    int i=0;

    static int j=0;

    VariableInit(){

       i=10;

       j=20;

    }

}

在首次使用该类的静态变量j或者创建该类时,java解释器会先找到VariableInit.class。然后载入VariableInit.class,此时,有关静态的初始化会被执行,且就在加载时执行一次。new VariableInit()这个操作会在堆上分配足够的存储空间,此时存储空间会被自动清零(相当于缺省值的初始化),再会执行所有变量的定义,最后执行构造函数。

所以以上类在创建对象时,首先对静态变量j初始化(如果之前没有调用过j的话),然后执行i的定义,最后执行构造函数。

测试:

System.out.println(VariableInit.j);

VariableInit variableInit=new VariableInit();

System.out.println(variableInit.j);

    输出结果:

    0

10 20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值