jvm内存管理机制(一)-----超级详细的java内存区域的总结
最近深入学习了一下Java虚拟机,通过《深入理解java虚拟机》(第二版)开始系统的总结学习了一波
首先学习的是运行时数据区域
运行时数据区域
运行时数据区域分为线程独享跟线程共享
关于线程独享
1)虚拟机栈(描述的是java方法执行的内存模型,每次执行都会创建一个虚拟帧,每一个方法执行的过程就对应这栈帧在jvm里面入栈到出栈的过程),
2)程序计数器(主要记录程序执行到哪一行代码),
3)本地方法栈(与虚拟机栈十分类似,虚拟机栈为虚拟机执行java方法,本地栈为native服务)都是独享的
线程共享
包括有:1)方法区(储存被虚拟机加载进去类信息)
2)堆(是被所有的线程共享的一块内存区域,虚拟机启动的时候创建)
书上面是这个图,我觉得不太好理解,自己画了一个,
对象创建的流程
譬如碰到new Student()先去加载student类(大致上是下面的这个过程)
内存分配的方式
1)指针碰撞
假设java堆中内存·是绝对规整的,所有用过的内存和没有用过的内存放在两边,中间有一个指针作为分界线,分配内存就是指针向空闲的空间那边挪动一段与对象大小相等的距离,这就是指针碰撞
2)空闲列表
如果java堆里面的内存不是规整的,已使用的内存和空闲的内存相互交错,虚拟机就得维护一个列表,记录哪里的内存可以用,分配的时候在列表里面找到一个足够大的空间划分给对象实例,并更新列表上的记录,
当然了选择那种分配方式还是java堆是否规整来决定,Java堆是否规整又由采用的垃圾收集器是否带有压缩功能决定,
对象内存布局
内存布局分为3部分
1)对象头(一部分用于储存对于自身运行的数据,另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定对象是哪个类的实例),
2)实例数据(对象真正储存的的有效信息,也是程序代码中所定义的各种类型的字段内容,在父类总定义的变量会出现在子类前,特殊的如果子类总有较窄的变量也可能会插入到父类变量的间隙里面),
3)对齐填充(并不是必然存在的,仅仅起到占位符的作用,一般当对象实例没有对齐的时候,就需要对齐填充来补全)
对象的访问定位
访问定位是什么
1)简单的说就是java程序通过栈上面的数据去操作堆上面的对象
访问定位分为几种形式?
1)句柄访问(会java堆上面会划出来一块内存当作句柄池,在栈上面的reference中储存的就是对象的句柄地址,句柄中包含了对象实例数据和类型数据各自的具体地址信息
2)直接指针访问,java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,reference中承诺的就是对象地址
他们之间有什么优势?
句柄访问的优势是reference中存储的是稳点的句柄数据,对象被移动的时候,只会改变句柄中的实例数据,reference本身不变,比较稳定
用直接指针访问,最大的好处就是速度快,节省了一次指针定位的时间,由于对象的访问在Java里面十分的频繁,积少成多后很乐观,但是在软件开发的范围来说,句柄访问也十分的常见
以上就是关于对Java内存区域的总结,每天总结一点点,积少成多,加油