图一:来自于参考链接(1)
1.Java虚拟机栈:描述的是Java方法的执行的内存模型
线程私有,每个方法在运行时否会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。我们经常把Java内存区域分为 堆内存 和 栈内存,这里的栈是指虚拟机栈,或者虚拟机栈中的局部变量表部分。
局部变量表存放了编译期可知的各种基本数据类型(8种基本类型)、对象引用 和 returnAddress类型(指向了一条字节码指令地址)
64位长度的long 和double 类型的数据会占用 2 个局部变量空间,其他类型占用 1 个。局部变量表所需的内存空间在编译期完成分配,当进入一个方法时,这个方法在帧中分配多大的局部变量空间是完全确定的,方法运行期间不会改变局部变量表的的大小。
2、Java 堆(Heap):
是Java虚拟机所管理的内存中最大的一块。被所有线程共享的内存区域,在虚拟机启动时创建。
此内存区的唯一目的就是存放对象实例。所有的 对象实例 以及 数组 都要在堆上分配
3、 方法区(永久代permanent generation):与堆一样更线程共享内存区域
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等
JDK1.7的HotSpot中,已经把原来放在永久代的字符串常量池移出
4、运行时常量池:是方法区的一部分。
class 除包含类的版本、字段、方法、接口等之外,还包含常量池(constant pool table)用于编译期生成的各种 字面量 和 符号引用,这部分内容将在类加载后进入方法区的运行时常量池 中存放。还会把翻译出来的直接引用也存储在运行时常量池中。
运行时常量池 相对于 class文件常量池 来说更具 动态性,并不是只有编译期产生的常量才能进入方法区常量池,运行期也可以将新的常量存放进 运行时常量池。【现在明白了吧,运行时常量池 和 我们平时提到的常量池(class文件中的常量池)不是一回事,参考链接(4)、(5)】(深入理解JVM中运行时常量池那部分内容非常明显的区分开了两个名词:)
class文件常量池(也就是常量池)存放编译期生成的各种字面量和符号引用,这部分内容在类加载后进入方法区运行时常量池存放。此常量池是编译期被确定,并且保存在已编译的.class文件中的一些数据。
运行时常量池相对于class文件常量池具有动态性,Java语言并不要求常量一定之在编译期才能产生,也就是并不只是编译完之后进入class文件常量池的内容才能进入运行时常量池,运行期间也可以将新的常量放入常量池
5.对象创建
虚拟机到一条new指令时,首先去检查这个这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被 加 载 、解析、初始化过,如果没有必须先执行相应的类加载过程。
Java内存是否规整决定了内存房分配采用的方式:规整-->指针碰撞,不规整-->空闲列表。考虑到线程安全问题,采用CAS配上失败重试方式 或者 将分配动作按照线程划分在不同的空间,即每个线程在Java堆中预先分配一小块内存(TLAB)那个线程需要分配内存就在那个线程的TLAB上分配
参考:
(1) http://blog.csdn.net/u010814766/article/details/46785425
(2) http://blog.csdn.net/zhoudaxia/article/details/26454421/
(3) http://blog.csdn.net/baidu_31657889/article/details/52315902
(4) http://www.cnblogs.com/holos/p/6603379.html
(5) http://www.jianshu.com/p/c7f47de2ee80