美文网首页Java基础
深入Java虚拟机笔记

深入Java虚拟机笔记

作者: 小鱼嘻嘻 | 来源:发表于2017-08-27 19:32 被阅读5次

    最近在看深入Java虚拟机,因为这本书理论为主,我之前看过前几章,没多久还是全忘了,为此这遍我想做点笔记,哪怕又忘了,也可以快速拾起来。

    Java内存区域和内存溢出异常
    内存区域介绍

    首先,来看看内存区域。java运行时的内存区域主要分为:程序计数器,堆区,栈区,方法区。

    • 程序计数器
      主要保存字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能。
    • 栈区
      主要保存的是基本数据类型,以及对象的引用。在这块内存区域会抛出两种异常:StackOverFlowError 这表示栈的深度不够;OutOfMemoryError 这表示无法申请到足够的内存空间了
    • 堆区
      这块区域是Java虚拟机管理的最大的一块区域,这块区域也是所有线程共享的区域,这块区域主要保存的Java对象,当这块内存区域不够的时候也会抛出OutOfMemoryError。这块区域的详细情况我们下面在介绍。
    • 方法区(永久代)
      这块区域主要保存的是常量,静态变量,类信息等,这块区域也是共享的,当这块区域内存不足的时候也会抛出OutOfMemoryError。
    对象的创建

    我们来分析一下Java中new一个对象的过程到底什么样的呢?
    首先,这条指令会去做一个check,检查一个常量池是否可以定位到一个类的符号的引用;接下来就是要在对内存创建一块内存空间了,分配内存空间有两种方式: 指针碰撞方式和空闲列表。

    • 指针碰撞
      首先,假设Java堆内存是绝对的规整,使用过的内存放一边,未使用过的内存放另外一边,中间放着一个指针作为分界点指示器。
    • 空闲列表
      如果内存不是规整的就没办法进行指针碰撞,虚拟机就必须维护一个空闲列表,那些是可用的那些是不可用的是通过这个空闲列表来记录的,因此目前大多数都使用空闲列表。如何划分内存空间也是一个很大的问题,因为这块区域是共享的,对象的分配是非常频繁的,在并发的情况下线程又不是安全的,如何保证内存分配不出问题呢?第一种:可以使用cas的方式,保证原子性;第二种:可以使用本地线程分配缓冲器(TLAB),也就是说每个线程在Java堆区域里预先分配一块内存,只有这块预先分配的内存使用完了才会使用同步操作。
    对象的内存布局

    对象在内存布局可以分为三块:对象头,实例数据,对象填充。

    • 对象头
      第一部分数据为:哈希码,GC分代信息,线程所持有的锁,偏向线程ID,偏向时间戳。
      第二部分数据为: 类型指针,对象指向它的类元数据的指针。
    • 实例数据
      对象存储的真正有效信息。
    • 对象填充
      没有什么含义,起到站位的作用。
    对象的访问

    对象的访问主流的方式是使用句柄和直接指针

    • 句柄
      Java堆中将划分出一块存储句柄,访问的时候先从Java栈到句柄池再到具体的对象。
    • 直接指针
      栈中保存的就是对象的引用,可以通过引用直接访问到具体的对象。
      这两种方式比较的话:直接指针更有优势,因为它会少移动一次指针。

    相关文章

      网友评论

        本文标题:深入Java虚拟机笔记

        本文链接:https://www.haomeiwen.com/subject/srkidxtx.html