一、JMM(内存模型)
在了解对象创建并分配内存前,首先了解一下Java的内存模型。Java编程不再像c++/c语言需要开发人员管理内存,而是将内存管理交给了JVM虚拟机,从而也将开发人员从内存管理中解脱出来。那么Jvm虚拟机是如何实现内存管理的呢?
内存划分
在JDK7之前,JVM启动时会创建堆区 (Heap) 和 方法区 (Method Area);而在JDK8以后,创建的为堆区 (Heap) 和 元空间 (MetaSpace)。而这两个区域都是线程共享,但线程也存在私有区域:程序计数器、本地方法栈、虚拟机栈 。我们今天将创建对象为其分配内存空间,那么它是存在那块区域呢?当然是堆区,那它如何在堆区存储、管理呢?那就得先了解一下堆区的划分。
二、堆区
堆区划分
堆区是JVM所管理的内存中最大的一块,堆区中几乎存放了所有对象的实例,既然存放了大量对象的实例及数组,那是如何管理呢?那就涉及到分代思想,堆区将每个对象当成有生命的个体将其划分为:新生代、老年代,新生代又被划分为三个区域:Eden(伊甸区)、s0(survivor)、s1(survivor)。
对象分配内存
- 创建一个新对象,Eden区就是对象最开始诞生的区域
- 如果Eden区内存充足时,直接为其分配内存
- 如果Eden区没有那么大的内存存储该对象,则触发YGC垃圾回收机制,通过整理Eden区的内存判断该对象是否可以被存储
- 如果通过YGC回收机制后发现Eden区有足够的空间可以存储该对象,则为其分配空间
- 如果已经触发YGC机制并回收了,内存空间依旧不充足,则考虑将其存储至老年代
- 如果老年代的内存充足,则为其分配空间
- 如果老年代的内存依旧不足以存储该对象,则触发FULL GC回收机制,通过整理老年代的内存,判断该空间是否可以存储该对象
- 如果可以存储该对象,则为其分配空间
- 如果还不可以存储该对象,那么该对象已经超出内存所剩的空间,则抛出内存溢出的异常
- 那么survivor区存在的意义是什么呢?
Enden区存储满时,会将一部分对象存储至survivor区,两个survivor区相当于是辅助,帮助Eden区存储管理对象实例、数组等- 其实Enden区存储满时,将一部分对象存储至s0,当触发YGC回收机制时,又会将对象存储至s1,连同s0中的对象存储至s1中。当对象从s0至s1的过程中对象的年龄则会+1,当对象的年龄超出15岁,则该对象将会被存储值老年代
- 其实Enden区存储满时,将一部分对象存储至s0,当触发YGC回收机制时,又会将对象存储至s1,连同s0中的对象存储至s1中。当对象从s0至s1的过程中对象的年龄则会+1,当对象的年龄超出15岁,则该对象将会被存储值老年代