APP下载

Think in java:Java的内存和垃圾回收机制

消息来源:baojiabao.com 作者: 发布时间:2024-05-08

报价宝综合消息Think in java:Java的内存和垃圾回收机制

1.Java中物件的储存资料的地方:

共有五个不同的地方可以储存资料.

1)暂存器.最快,因为位于处理器的内部,暂存器按需求分配,不能直接控制.

2)堆叠.位于通用RAM,通过堆叠指标可以从处理器那里获得直接支援.堆叠指标向下移动,分配新的内存,向上移动,则释放那些内存.Java系统必须知道储存在堆叠内的所有专案的确切的生命周期.

3)堆.编译器不需要知道储存的资料在堆里活多长时间.

4)常量储存.通常直接放在程式码内部.

5)非RAM储存,如果资料完全存活与程式之外,那么它可以不受程式的任何控制,在程式没有执行的时候也存在,其中最基本的例子是流物件和持久化物件.

2.Java资料的储存:

根据《Java虚拟机器规范》的规定,执行时资料区通常包括这几个部分:程式计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。

1)程式计数器,程式计数器是一块较小的区域,它的作用可以看做是当前执行绪所执行的字节码的行号指示器。在虚拟机器的模型里,字节码指示器就是通过改变程式计数器的值来指定下一条需要执行的指令。分支,循环等基础功能就是依赖程式计数器来完成的。在多执行绪中,需要通过程式计数器才可以了解到当前执行绪执行到哪一个位置,在下次抢到执行权后,从原来的位置开始.因此,程式计数器是执行绪私有的.如果虚拟机器正在执行的是一个Java方法,则计数器指定的是字节码指令对应的地址,如果正在执行的是一个本地方法,则计数器指定问空undefined.

2)Java栈也被称为虚拟机器栈,和程式计数器一样也是执行绪私有的,生命周期和执行绪相同,虚拟机器栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会建立一个栈帧用于储存区域性变量表,操作栈,动态连结,方法出口等资讯。每一个方法被呼叫的过程就对应一个栈帧在虚拟机器栈中从入栈到出栈的过程。虚拟机器栈又分为区域性变量表(储存方法所要用到的区域性变数),算子栈(资料结构里用来执行计算过程),指向执行时常量池的引用,方法返回地址以及附加讯息.Java栈是Java方法执行的内存模型.

3)本地方法栈:Java栈是为执行Java方法服务的,本地方法栈是为执行本地方法服务的.

4)堆:在Java中用来储存物件本身(包括物件中的成员变数,阵列),Java的自动垃圾回收机制主要就是回收这一部分的空间.堆是所有执行绪共享的,Java虚拟机器只有一个堆.

5)方法区:方法区和堆一样也是被执行绪所共享的,在方法区中,储存了每个类的资讯(包括类的名称,方法资讯,字段资讯),静态变数,常量以及编译器编译后的程式码等。在方法区中有一个重要的部分叫做常量池,当类和界面被载入到JVM中,对于的常量池就被加载出来.在执行期间可以把新的常量放入常量池中.

3.Java的自动垃圾回收机制:终结处理和垃圾回收:

1)finalize方法详解:

finalize方法为Object的protected方法,子类可以覆盖此方法实现操作,GC在回收物件前呼叫此方法.不建议用finalize方法完成“非内存资源”的清理工作,但建议用于:① 清理本地物件(通过JNI建立的物件);② 作为确保某些非内存资源(如Socket、档案等)释放的一个补充:在finalize方法中显式呼叫其他资源释放方法.

首先,大致描述一下finalize流程:当物件变成(GC Roots)不可达时,GC会判断该物件是否覆盖了finalize方法,若未覆盖,则直接将其回收.否则,若物件未执行过finalize方法,将其放入F-Queue伫列,由一低优先级执行绪执行该伫列中物件的finalize方法.执行finalize方法完毕后,GC会再次判断该物件是否可达,若不可达,则进行回收,否则,物件“复活”.(也就是说当物件变成GC Roots不可到达的时候,物件先执行finalize方法,此时由于存在方法的呼叫,物件复活(但是内部标记显示已经呼叫过finalize方法)之后再判断的时候,如果仍然为GC Roots不可到达,且内部标记显示已经呼叫过finalize方法,则直接回收).可以手动的在finalize方法内部显示关闭资源或者复活物件.

另外由于finalize方法呼叫的不确定性(实际上垃圾回收执行绪的优先级是较低的),因此极有可能出现了垃圾但是未被及时回收.

2)垃圾回收器工作原理:

其他系统的垃圾回收机制:

①引用计数法

每个物件包含一个引用计数器,当有引用连线至物件的时候,引用计数+1,当引用离开作用域或被置位null的时候,引用计数-1.垃圾回收器会在含有全部物件的列表中进行遍历,如果发现某个物件计数值变为0的时候,则会立即释放该物件.但是这个方法有个缺陷,也就是物件之间存在循环呼叫的情况下,则会出现物件应该被回收,但是计数器却不为0的情况.如下程式码演示了循环呼叫:

public class Test2 {

public static void main(String[] args) {

Dog d=new Dog();

Cat c=new Cat();

d.cat=c;

c.dog=d;

     d=null;

     c=null;

}

}

class Dog {

public Cat cat;

}

class Cat {

public Dog dog;

}

②优化的垃圾回收:

对于任何活的物件,一定能追朔到其存活在堆叠或者静态储存区之中的引用.由此,如果从堆叠和静态储存区域开始,遍历所有的引用,就能找到活的物件.对于发现的每个引用必须追踪它所引用的物件,然后是此物件包含的引用,知道根源于堆叠和静态储存区的引用所形成的网络全部被访问为止.没有被访问到的物件即是需要被垃圾回收机制处理的物件.

③Java的垃圾回收机制:

停止复制:先暂停程式的执行,然后将所有存活的物件从当前堆复制到另一个堆,没有被复制的全都是垃圾.当物件被复制到新堆的时候,它们是一个挨着一个的,所以新堆能紧凑排列.但是在Java中,大型物件仍然不会被复制.内含小型物件的那些块被复制和整理.

标记清扫:从堆叠和静态储存区出发,遍历所有的引用进而找出所有存活的物件,每当找到一个存活的物件就会设定一个标记,最后当所有标记工作都完成的时候,没有被标记的物件将会被释放.所以剩下的堆空间都是不连续的.Java虚拟机器将会监视:如果所有的物件都很稳定,垃圾回收器的效率降低的话,就切换到"标记清扫"模式,同样虚拟机器会跟综标记清扫的结果,如果堆空间中出现很多碎片,就会切换回停止复制方式.这就是Java虚拟机器的垃圾回收机制的"自适应"技术.

4.方法接受基本资料型别时候的自动型别提升:

传入byte型别的方法:byte(优先匹配)==>short==>int==>float==>double.(byte资料不能传入char引数)

传入char型别的方法:char(优先匹配)==>int==>float==>double(跳过short,char资料不能传入short引数)

传入short型别的方法:short(优先匹配)==>int==>float==>double.

传入int型别的方法:int(优先匹配)==>float==>double.

传入float型别的方法:float(优先匹配)==>double

传入double型别的方法:只有double的引数才能匹配.

原文:https://www.cnblogs.com/hlhdidi/p/5642387.html

2019-07-17 01:51:00

相关文章