JAVA内存区域——运行时数据区

程序计数器(线程私有)
我们可以认为它是当前线程正在执行的字节码的行号指示器,Java中多线程是通过分割时间片来实现的,因此为了使线程回来能够接着执行字节码,我们就需要在每条线程中都有程序计数器来存储行号,这样下次就可以接着执行。
Java虚拟机栈(线程私有)
存栈帧(下面有讲),它是有大小限制的,当方法调用链太长时就OOM了。
本地方法栈
类似虚拟机栈,只不过它负责Native方法,而虚拟机栈负责Java方法。所以它应该也是线程私有的
Java堆又叫GC堆(线程共享)
它是GC的主战场,存放所有的实例对象,听说使用所有这个词不太对,因为随着逃逸分析技术(后面有讲)的发展,对象不完全都在Java堆中了
方法区又叫永久代(线程共享)
用于存放加载的类信息、常量、静态变量、即时编译器编译后的代码等(并不太懂)
运行时常量池
它属于方法区的一部分。编译的Class文件中有一项信息叫常量池,用于存放编译时期生成的字面量以及符号引用(不太懂)。运行时常量池就是Class文件的常量池再加上运行期间产生的新常量,即具备动态性。
逃逸分析
当一个对象在方法中被定义后,它可能被外部方法引用,或者被别的线程访问,这两种情况分别叫做方法逃逸以及线程逃逸
若能够证明一个对象不会出现逃逸现象,那么就可以对它做一些优化:

  • 栈上分配——将对象分配到虚拟机栈上而不是Java堆中,由于虚拟机栈是线程私有的,线程凉它就凉,所以栈上分配的对象也一起凉,那么就不需要垃圾回收,很棒棒
  • 同步擦除——既然不会被别的线程访问,那就不存在同步问题,所以就可以去掉码农写的同步代码(同步是一个相对耗时的操作)
  • 标量替换——(标量:原始数据类型,不可再分)和栈上分配有点类似?把聚合量(对象)拆开,拆成基本类型,放在虚拟机栈中,听说栈中的标量有很大概率被安排,性能变好
栈帧
【JAVA内存区域——运行时数据区】它是虚拟机栈的栈元素,是一个数据结构。它与方法一一对应,一个方法有一个栈帧,其中记录方法的相关数据:局部变量表、操作栈、动态链接、返回地址等。下面说一下其中的局部变量表。
局部变量表 变量值存储空间,它的大小在编译成Class文件时就已经确定了。它存储基本类型boolean、byte、char...以及reference。为什么大小确定呢?那局部变量是一个对象呢,比如List,可以不断的添加元素,那么大小不就是不确定的吗?答案是,对于对象而言,局部变量表中只是存着它的引用而已,实际上实例是存在Java堆中的,所以List再怎么变大也不影响引用。

    推荐阅读