第二章 java内存区域与内存溢出异常
2.2 运行时数据区域
1.程序计数器:为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,(线程私有内存)注:唯一一个没有规定任何内存溢出异常(OutOfMemoryError)情况的区域
2.java虚拟机栈:java方法在执行的同时创建的一个栈帧(用于存储局部变量表等),也就是常常提到的栈内存。 局部变量表的空间在编译期间完成分配
3.本地方法栈(Native Method Stack):给非java语言使用的虚拟机栈;有些虚拟机将两者合二为一(Sun HotSpot虚拟机,就是最常用的那个)
4.java堆:存放对象实例、数组,是被所有线程共享的一块内存区域,在虚拟机启动时创建。“GC堆”,垃圾收集器管理的主要区域。
5.方法区:各线程共享的内存区域。存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码(我理解是动态生成的反射类)。hotSpot虚拟机在JDK1.7之前,将永久代来实现方法区,1.8之后使用元数据来实现方法区。
6.运行时常量池:属于方法区的一部分,存放编译期间生成的字面量和符号引用,在类加载时放到常量池中;此区域具有动态性,最长用到的是String.inern()方法
7.直接内存(堆外内存):此内存不属于JVM,但是此内存如果超出了最大限定也会抛出OOM异常。此内存是由于NIO类的产生。
图解:
1.检测是否能在常量池中定位到此类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
2.分配内存的两种方式:
指针碰撞;
空闲列表。
选择哪种方式取决于java堆是否规整,而java堆是否规整又取决于垃圾收集器是否存在压缩规整功能。
解决分配内存时线程不安全的两种方式:
CAS+失败重试;
本地线程分配缓冲(TLAB)。
3.保证了对象的实例字段在Java代码中可以不赋初始值就直接使用
对象的访问方式:句柄和直接指针。HotSpot虚拟机采用直接指针,因为速度快。