深入理解jvm虚拟机第二章总结

1运行时数据区

对于线程隔离的数据区其实就是线程私有的数据区。每个线程都拥有自己的这三个部分

1.程序计数器

   可以理解为cpu中的pc就是为了记录当前线程执行到哪条指令,也用于恢复现场,pc寄存器中记录的是虚拟机栈的的指令地址,如果当前执行的native方法,则值为null。

2.虚拟机栈

  用于存放当前线程中执行的方法、产生的变量,返回值等。在此线程中每调用一个方法都会产生一个栈帧,方法调用完之后,栈帧出栈。

3.本地方法栈

  调用非java的代码,即系统本身的c/c++方法。

以上三个线程私有,生命周期同线程

4 堆

  java 绝大多数的对象和数组都要存放在 其他少部分要依照java逃逸机制。

5.方法区

  存储被虚拟机加载的 类信息,常量信息,静态变量等

6.常量池

  在早前的常量池都放在方法区内部,但是在jdk1.7后字符串常量池不被放在方法区中了,可以通过给方法区设定大小,往list中add String进行验证

上面的6个内存区域可以认为是java本身的内存,给虚拟机分配的内存等于上面6个区域和,每个区域都会抛出oom异常,在本地方法栈和虚拟机栈都会抛出sof(stackoverflow)。

7直接内存

  这是用于nio的时候,本地方法栈中的方法可以直接分配java堆外的内存,然后在java堆中创建DirectByteBuffer指向这块空间进行引用,避免了在native堆和java堆直接的数据copy,这块大小不受jvm内存大小限制,受本机大小限制。

2对象的创建,内存布局,定位

 1.对象创建

     当虚拟机遇到一条new指令的时候,回去检查相关的类有没有被加载,解析,初始化过,没有就先去执行上述过程,接着为对象分配内存空间,关于内存分配,有两种做法

 1.1指针碰撞,就是在堆上有一个指针,维护被使用的内存,在指针左右两侧分别是被使用过的空间和未使用的空间,当需要分配空间时,就将指针往未分配的空间移动需要分配的空间大小。

1.2空闲列表,维护一个list,记录着哪块内存被分配,哪块没有被分配。

关于jvm使用上述的哪种方式,取决于jvm的垃圾回收器,书上说是Serial,parnew等使用指针碰撞,cms使用空闲列表

(我的理解:在垃圾回收中,基于标记复制和标记整理的算法,一般都是用的是指针碰撞,在使用标记清除的,都是使用空闲列表的方式)

jvm是多线程的,所以要考虑到多线程情况下jvm的内存分配是否安全,jvm采用了cas的方法保证线程安全。

分配完内存后就要考虑初始化的问题,这牵扯到内存布局,给对象布局中的变量赋值完之后才给对象的数据赋值为默认值,最后调用init方法(应该是构造器),对象才算new完成。

2对象内存布局

对象内存布局分为3个部分:对象头,实例数据,对齐。

对象头又分为markword和Klass point 。markword长度依照操作系统的位数来看,64位就64b,32位就32b,Klass point也是一样的,但是如果开启了指针压缩(在jvm虚拟机中设置),则会变为32位,然后如果对象是数组,则还有一个数组长度,32位(因为数组长度不会超过int大小),对象头存储的是哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等信息。 classpoint是指这个对象是属于哪个类的。

实力数据类中的数据,长度就是按照原来的正常计算,long/double 8byte,int  4byte,short/char 2byte,bytes/boolean 1byte,oop(odinary object point)查不到多长。。

剩下的对其部分,就是看系统是多少位来计算的,如果是32位 上面计算出来的长度要为4的整数倍,64位为8的整数倍。

3.对象定位

   对于当下的语言有两种方式实现指针

1.句柄

这个到对象实例数据的指针指的其实是数据变成二进制之后是存在哪里的,需要到对象类型数据的指针是因为将数据变为0和1存在某个地方了,但是不知道他存的是什么,是每个byte都是boolean还是每连着4个byte是一个long,对于计算机而言数据在那一块只有数据部分,没有数据的解释部分,而这个对象类型数据的指针指向了方法区中对象加载的地方,相当于一个模板。告诉计算机对象实例数据的指针指向的区域是分别存储什么的。  

而使用句柄的好处是,当需要移动实例池中的数据的时候(垃圾回收),只需要修改句柄池中的的数据实力指针部分,不需要去修改引用部分,

2.直接指针

对于直接指针的方法,相较于句柄,少了一次指针定位的过程,速度较快。

hotspot的虚拟机采用的是第二种情况

(个人见解,讲道理采用句柄更好啊,对于GC的时候,减少了很多的修改,如果有多个线程引用一个对象,这个对象需要去移动了,那么要修改引用了这个对象的变量,将新地址赋值给变量,问题是真个变量怎么去寻找,就成了一个很难解决的问题,或许是因为正常情况下,java对象不会被很多对象引用,就像设计模式中那样,很少有创建一个对象给其他对象引用的,没开发经验也都不清楚。)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值