各区域保存的内容及特点
堆
参数控制
对象创建的过程及内存分配
下面讨论的范围是使用普通的 new 的方式来创建对象
- 第二步中如何分配内存?分配内存时如何解决并发问题?
- 初始化内存配置做了什么事情?对象的域变量初始值是什么?
- 初始化内存必要配置主要是清空内存值,设置类的元数据,设置hashcode 等
- 域变量的默认值取决于该类型在内存被清空状态下的含义
- 比如 boolean 类型默认为 false
- long 类型默认为 0
- 给对象分配内存有两种方式,一种是指针碰撞,一种是空闲列表,那么什么情况下使用指针碰撞,什么时候使用空闲列表?是什么因素决定使用不同的分配策略?
- 使用指针碰撞的前提是内存是要规整的,而内存是否规整取决于垃圾回收器的类型,如果使用标记整理算法的垃圾回收器则可以使用指针碰撞的分配形式。
方法区
运行时常量池
- 运行时常量池是方法区一部分
- Class 文件中除了有类的版本,字段,方法,接口等描叙信息外,还有一项信息是常量池表,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放在方法区的运行时常量池中。
运行时常量池和常量池的区别是具备动态性,Java 中常量不是只有在编译期才可以生成,也可以在运行期间将新的常量放入池中,比如
String.intern()
方法会出现的异常
OutOfMemoryError
参数配置
-XX:PermSize=6M
jdk7 及以前的配置形式,限制永久代的大小-XX:MaxPermSize=6M
jdk8 及以后的配置形式,限制元空间的大小
虚拟机栈
局部变量表的大小在编译期就是确定的,也就是在进入一个方法之前栈的局部变量表大小就明确了,在运行期间大小是不会改变的。
会出现的异常
OutOfMemoryError
- 单线程情况下都不会出现 OutOfMemoryError,只会有 StackOverflowError 错误
- 我们所说的虚拟机栈只是针对一个线程而言的,如果多个线程在执行,每一个线程都对应一个虚拟机栈,那一共就有多个虚拟机栈了。
StackOverflowError
-Xss eg:
-Xss128k
是将栈的大小配置成 128k
程序计数器
当前线程所执行的字节码的行号指示器(当前线程执行的位置),当 cpu 切换到当前线程的时候,需要知道之前已经执行到了哪里。
对象的内存布局
- 对象在堆内存的存储布局可以划分为三个部分
- 对象头: 包含两类信息
- 用于要出对象自身的运行时数据:如果是32位虚拟机则有 32 个bit,若是 64 位虚拟机则是 64bit,称之为 Mark Word
- HashCode
- GC 分代年龄
- 锁标志
- 线程持有的锁
- 偏向的线程id
- 偏向的时间戳
- 类型指针: 指向它的类型元数据的指针
- 如果对象是 Java 数组,则对象头中海有一块用于记录数组长度的数据
- 用于要出对象自身的运行时数据:如果是32位虚拟机则有 32 个bit,若是 64 位虚拟机则是 64bit,称之为 Mark Word
- 实例数据
- 对齐填充
- 使用句柄的方式进行访问
- 使用直接指针的形式进行访问(HotSpot 中使用这种形式进行访问的)