[深入理解JVM] 第一章 内存

ref: https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/jvm/Java内存区域.md

  • java虚拟机内存区域分布
    • JDK1.8之前
      [外链图片转存失败(img-s6swXMBF-1564190976174)(leanote://file/getImage?fileId=5d36bcc72657b84172000000)]
    • JDK1.8
      [外链图片转存失败(img-HaRoeZCS-1564190976175)(leanote://file/getImage?fileId=5d36bcdd2657b84172000001)]

以下6个是Java虚拟机运行时数据区:

  1. 程序计数器

    • 当前线程的字节码的行号指示器;
    • 每个线程都需要有一个独立的程序计数器;
    • 不会抛出OutOfMemoryError异常,其他5个都会。。。。
  2. Java虚拟机栈

    • 为虚拟机执行java方法(字节码)服务;
    • 线程私有的:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数帧、方法出入口;
    • 局部变量表:基本数据类型、对象引用和returnAddress类型;
  3. 本地方法栈

    • 为虚拟机使用到的native方法服务;
  4. Java堆

    • 被所有线程共享;
    • 所有对象实例以及数组都要在堆上分配;
    • 其中有进一步划分,为了更好的垃圾回收;
    • Classloader加载一个类并把类型信息保存到方法区后,会创建一个Class对象,存放在堆区的,不是方法区,它为程序提供了访问类型信息的方法;Hotspot中Class类是存储与方法区的;
  5. 方法区

    • 线程共享的;
    • 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
    • 此处的垃圾回收主要针对常量池的回收和对类的卸载;
  6. 运行时常量池

    • 方法区的一部分;
    • Class文件中除了有类的版本、字段、方法、接口等信息外,还有一项信息是常量池,用于存放编译器生成的各种字面量和符号引用;
      [外链图片转存失败(img-NMh7I4Ug-1564190976177)(leanote://file/getImage?fileId=5d36c5272657b84172000003)]
  • 直接内存
    • 不是虚拟机运行时数据区的一部分;
    • NIO(New Input/Output)类通过Native函数库直接分配堆外内存,通过存储在java堆中的DirectByteBuffer对这块内存的引用进行操作;
    • 可以提高性能,避免了在Java堆和Native堆来回复制数据;
    • 虽然不受Java堆大小的限制,但受到本机内存的限制;

  • 对象创建过程
    [外链图片转存失败(img-b3dtLd6z-1564190976177)(leanote://file/getImage?fileId=5d36c5932657b84172000004)]

    • 内存分配
      [外链图片转存失败(img-VE3rTTfc-1564190976178)(leanote://file/getImage?fileId=5d36cb362657b84172000005)]
    • 并发问题
      [外链图片转存失败(img-vVLG5CuA-1564190976178)(leanote://file/getImage?fileId=5d36cb592657b84172000006)]
  • 对象的内存布局

    • Hotspot 虚拟机的对象头包括两部分信息
      1. 第一部分用于存储对象自身的自身运行时数据(哈希码、GC 分代年龄、锁状态标志等等),
      2. 另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例。
    • 实例数据部分是对象真正存储的有效信息,也是在程序中所定义的各种类型的字段内容。
  • 对象的访问定位

    • Java 程序通过栈上的 reference 数据来操作堆上的具体对象;
      1, 使用句柄访问:如果使用句柄的话,那么 Java 堆中将会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息;
      [外链图片转存失败(img-uG2oPtsO-1564190976179)(leanote://file/getImage?fileId=5d36cd692657b84172000007)]
    1. 直接指针访问: 如果使用直接指针访问,那么 Java 堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而 reference 中存储的直接就是对象的地址。
      [外链图片转存失败(img-qhtHlm4a-1564190976179)(leanote://file/getImage?fileId=5d36cd9b2657b84172000008)]
    • 这两种对象访问方式各有优势。使用句柄来访问的最大好处是 reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。使用直接指针访问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值