您的位置:首页 > 其它

JVM学习笔记(1)——自动内存管理机制(上)

2018-02-27 14:58 148 查看
Java虚拟机在执行java程序的时候会将内存分为多块来管理,每一块内存都有其不同的作用,以及创建和销毁的时间。


1.程序计数器程序计数器是一小块内存,可以说是当前线程的信号指示器,也就是说字节码解释器通过改变程序计数器的值来选择执行下一条指令。而java多线程机制中,一个处理器只会执行一条线程中的指令,因此每一条线程都要有一个程序计数器,所以各个计数器之间不相互影响,彼此独立,因此称这块内存是"线程私有"的内存。如果java虚拟机正在执行一个java方法,那该线程的计数器中存的就是正在执行的虚拟机字节码指令的地址。注意: 此内存是java虚拟机中唯一没有规定OutofMemoryError异常的地方!!2.java虚拟栈这玩意也是线程私有的,并且生命周期跟线程是一样的。他是java执行方法时候的内存模型,每次执行一个方法,就会创建一个栈帧来存储局部变量,操作数,动态链接和方法出口等东西。每一个方法的调用过程就可以对应到每一个栈帧的入栈道出栈的过程。当线程请求的栈深度大于虚拟机所允许的最大深度时,就会报StackoverError。3.本地方法栈本地方法栈和java虚拟栈的区别就是虚拟机栈为虚拟机执行java方法,而本地方法栈为虚拟机执行native方法服务4.java堆java堆是java虚拟机所管控的内存中最大的一块,是所有线程共享的一块内存,这块内存的目的就是为了存放对象实例,绝大部分对象都是在这块内存上分配内存。同时,java堆也是java的垃圾回收装置管理的区域,常被称为"GC堆"。5.方法区和java堆相似,也是线程共享的内存块,用来储存虚拟机加载的类信息和常量,静态变量等.... 方法区中包含了运行时的常量池,Class文件中除了编译产生的版本,字段,方法,接口等变量外,还有的就是常量池,用来储存编译产生的字面量和符号引用。————————————————————————————————————————————————————了解了基本的内存区域后,接下来就是讲解类的实例化过程了。1.对象的创建


加载检测完成后,就从java堆中分出一块内存分配个这个对象,接着引入两种假设:“指针碰撞":指的是java堆中未用的内存和已用的内容是区分开的,通过一个指针作为分界点的指示器,这样的话我们在创建对象的时候只需从未用的内存中移动一部分内存到已用的内存区中即可。"空闲列表":指的是java堆中的未用和已用的内存是交错分布的,那就需要用一个列表来维护,记录哪些内存是可用的,在创建对象时找到一块足够大的内存分配给对象实例即可。使用哪一种受到垃圾回收机制的影响,由垃圾回收器是否有压缩整理功能决定,这就涉及到不同的垃圾回收算法,后续内容会仔细讲解。要知道对象在java虚拟机中的创建时相当繁琐的过程,因为在高并发下,比如说现在A指针指向了一块内存S来作为对象A的分配内存,指针A还没来得及修改这块内存的归属的时候,另一个线程的指针B已经把这块内存S给用了,这就很尴尬了.. 对于这个问题,有两种解决方法,第一种就是在分配内存空间的时候进行同步处理(CAS方法),第二种则是是在java堆中给每一个线程先提前分配一块内存,称为本地内存分配缓冲——TLAB,哪个线程要内存就在他所在的TLAB中分配。当然如果这块内存用完了,那就只能同步锁定了~内存分配后,java虚拟机把分配的内存空间都初始化为0(除了对象头之外),需要注意的是,如果使用TLAB,那么这一过程会提前到TLAB执行的时候。对象头:储存着对象是哪个类(存在一个类型指针指向所属的类),怎样找到它的元数据信息,对象的哈希码,对象的GC分代年龄等等信息,在初始化的时候虚拟机会进行设置。虚拟机执行完毕之后,才会执行init,这时候对象才被真正创建出来,供程序员使用。补充对齐:


2.对象的访问java程序通过java栈上的reference数据来操作堆上的具体对象,reference则需通过java虚拟机去访问java堆中的对象。方式有两种:




两种方式各有各的优势 通过句柄访问的话 数据在reference中存储稳定,不需要改变,在操作对象时只需改变句柄中的实例数据指针。 而通过直接指针访问速度更快,但是这类开销积少成多也会十分麻烦。以上则为本章的主要内容归纳,对理解java底层的执行方式还是很有帮助的~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JVM