堆对于一个jvm进程来说是唯一的,一个进程只有一个jvm,但是进程半酣多个线程,多个线程共享一个堆。
也就是说,一个jvm实例只存在一个堆,同时对也是Java内存管理的核心区域。
Java堆区域的大小在jvm启动时就已经被确定下来了,是jvm管理的最大的一块内存空间,但对的大小也是可以调节的。
《Java虚拟机规范》规定对可以处于物理上不连续的内存空间中,但在逻辑上他应该被视为是连续的。
所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区,在《Java虚拟机规范》中对Java堆的描述是:所有的对象实例以及数组对象都应当在运行时分配在堆上。数组共和对象永远不可能储存在栈上,因为栈中保存引用的地址,这个引用会指向对象或者数组在堆中的位置。
在方法结束后,堆中 的对象并不会被马上移除,仅仅是在垃圾回收时才会被移除。对GC指向垃圾回收的重点区域。
在Java1.7之前堆内存在逻辑上分为:新生代+养老区+永久区
● 新生区 又被划分为Eden区和Survivor区
● 养老区
● 永久区
在Java1.8后分为:新生区+养老区+元空间
●新生区 Young/New 又被划分为Eden区和Survivor区
● 养老区
● 元空间
年轻代与老年代
在jvm中存储的对象可以被划分为两类:
- 一类是生命周期较短的瞬时对象,之类对象的创建消亡都非常迅速
- 另一类对象的生命周期却非常长,在某些极端的情况下还能够与jvm的上明周期保持一致
Java堆区进一步细分的化还可以划分为YoungGen年轻代和OldGen老年代
其中年轻代又可以划分为Eden空间、Survivor0和Survivor1空间也叫做from、to区
那么对象是如何进行分配的呢?
为对象分配内存是意见非常严谨和复杂的任务,jvm的设计者们不仅需要考虑内存如何分配、在哪里分配等问题,并且由于内存分配算法与内存回收算法密切相关,所以还需要考虑GC完成垃圾回收后在内存空间产生的内存碎片。
- new的对象先放到Eden也就是伊甸园区,此区域有大小限制
- 当伊甸园区的空间被填满时,程序还在创建新的对象,jvm的垃圾回收器将对伊甸园进行垃圾回收(MinorGc),将伊甸园中不在被其他对象所引用的对象进行回收,再将新家在的对象放入到伊甸园区
- 之后将伊甸园中剩余的对象移动到s0区
- 如果再次触发垃圾回收,此时上次幸存下来的放到s0区的,如果没有被回收就会被放到s1区
- 如果再次经历垃圾回收,此时会从新放回s0区,接着再去s1区
- 进入养老区的次数默认是15次
- 在养老区,相对悠闲.当养老区的内存不足时,再次触发Gc(MajorGc)进行养老区的内存清理
- 若在养老区执行了MajorGc之后发现依旧无法进行对象的保存就会报oom异常
● 针对幸存者s0,s1区的总结:复制之后有交换,谁空谁是to
● 关于垃圾回收:频繁在新生区收集,很少在老年代收集,几乎不再永久代和元空间进行收集