美文网首页
JVM 运行时数据区域简述

JVM 运行时数据区域简述

作者: 疯狂的哈丘 | 来源:发表于2017-09-04 23:06 被阅读0次

    最近开始看《深入理解JVM虚拟机》。为了记得更牢固,方便以后复习。做好读书笔记。

    Jvm内存模型.png
    1. 如果当前线程执行的是一个Java方法,那么计数器记录的是它执行字节码指令的位置。如果执行的是本地Native方法,那么计数器值值为空。另外,此内存区域是JVM虚拟机中唯一一个没有规定任何OutOfMemoryError的区域。
    2. 如果请求的栈深度超过虚拟机所允许的栈深入,会抛出StackOverflowError。如果虚拟机栈可动态扩展(大多数的虚拟机都可动态扩展),当扩展无法申请到足够的内存时,就会抛出OutOfMemoryError。
    3. 和虚拟机栈一样会抛出StackOverflowError和OutOfMemoryError。
    4. 一般来说,所有的对象实例和数组都要在堆上分配。但是随着JIT编译器的发展和逃逸分析技术的日渐成熟,所有的对象都分配上堆上也就不那么绝对了。如果堆的内存不够,无法再为新的实例分配内存,且堆无法扩展时(大部分虚拟机都是可扩展的,通过-Xmx和-Xms控制),会抛出OutOfMemoryError。
    5. 当方法区无法满足内存分配需求时,将抛出OutOfMemoryError。

    除了以上内存块,还要补充一个 直接内存

    直接内存

    直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内也被频繁的使用,而且也可能导致OutOfMemoryError异常出现。例如JDK1.4中新加入的NIO就是使用Native函数库分配对外内存。

    对象的创建

    虚拟机遇到一条new指令的时候,会先去检查这个指令能否常量池在常量池定位到一个符号引用,如果得到这个符号引用,就检查它代表的类是否已经被加载、解析、初始化过(初始化静态变量,执行static块代码等)。如果没有,那需要先执行类加载过程。
    在类加载完成后,就为新的实例对象分配堆内存。所需的内存大小在类加载完成后就已经完全确定了。为对象实例分配空间其实就是从Java堆中划分一块确定大小的内存出来。
    一些要点:

    1. java堆如何给实例分配空间的
    • 每个对象分配的内存空间是固定的。
    1. 怎么解决分配空间时遇到的并发问题——(同步和TLAB缓存)
    • 使用CAS进行分配内存(失败后重试)
    • 使用TLAB进行分配。TLAB是每个线程都会分配到的一部分内存空间(也属于堆内存的一部分),先在这块内存上分配,TLAB内存块满了后,将TLAB同步到堆内存中去(同步的过程是加锁的,所以是线程安全的),然后新开一块新的TLAB空间给线程。

    对象的内存布局

    实例内存空间分三大块:对象头、实例数据、对齐填充

    • 消息头存储的一部分是对象运行时数据(如hash码、GC分带年龄、锁状态标志等,32位系统架构下就32bit),还有一部分时指向它所属类的指针
    • 实例数据部分就是真正的存储数据了。包括父类继承下来的信息
    • 对齐填充不是一定存在的。因为要求HotSpot要求对象起始位置必须是8字节的整数倍。所以不够就填充。

    对象的访问定位

    1. 通过句柄访问——需要在java堆中管理一个句柄池
    2. 直接指针访问——HotSpot采用这种

    字符串池的理解

    String str1 = new StringBuilder("计算机").append("软件").toString();
    System.out.println(str1.intern() == str1);
    String str2 = new StringBuilder("ja").append("va").toString();
    System.out.println(str2.intern() == str2);
    

    在jdk6下面两个都是输出false,jdk7的时候一个 true false.
    产生差异的原因是: 在JDK1.6中,intern()方法会把首次遇到的字符串实例复制到永久代,返回的也是永久代的这个实例的引用,而由StringBuilder创建的字符串实例在java堆上,所以永远都是false。
    jdk7中,intern()方法不在复制实例,只是在常量池中记录首次出现的实例引用,因此intern()方法返回的和由StringBuilder.创建的字符串是同一个。
    由于java这个常量是虚拟机内置的,所以不符合首次出现的实例,指向的就不一样。

    学会模拟JVM堆内存溢出、虚拟机栈和方法栈溢出、方法区和运行常量池溢出、本机直接内存溢出

    相关文章

      网友评论

          本文标题:JVM 运行时数据区域简述

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