堆内存结构是怎么样的?

Posted cag2050

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆内存结构是怎么样的?相关的知识,希望对你有一定的参考价值。

站在垃圾收集器的角度来看,可以把内存分为新生代与老年代。内存的分配规则取决于当前使用的是哪种垃圾收集器的组合,以及内存相关的参数配置。往大的方向说,对象优先分配在新生代的Eden区域,而大对象直接进入老年代。

第一, 新生代的Eden区域,对象优先分配在该区域,同时JVM可以为每个线程分配一个私有的缓存区域,称为TLAB(Thread Local Allocation Buffer),避免多线程同时分配内存时需要使用加锁等机制而影响分配速度。TLAB在堆上分配,位于Eden中。

第二、新生代的Survivor区域。当Eden区域内存不足时会触发Minor GC,也称为新生代GC,在Minor GC存活下来的对象,会被复制到Survivor区域中。我认为Survivor区的作用在于避免过早触发Full GC。如果没有Survivor,Eden区每进行一次Minor GC都把对象直接送到老年代,老年代很快便会内存不足引发Full GC。新生代中有两个Survivor区,我认为两个Survivor的作用在于提高性能,避免内存碎片的出现。在任何时候,总有一个Survivor是empty的,在发生Minor GC时,会将Eden及另一个的Survivor的存活对象拷贝到该empty Survivor中,从而避免内存碎片的产生。

第三、老年代。老年代放置长生命周期的对象,通常是从Survivor区域拷贝过来的对象,不过当对象过大的时候,无法在新生代中用连续内存的存放,那么这个大对象就会被直接分配在老年代上。一般来说,普通的对象都是分配在TLAB上,较大的对象,直接分配在Eden区上的其他内存区域,而过大的对象,直接分配在老年代上。

第四、永久代。如前面所说,在早起的Hotspot JVM中有老年代的概念,老年代用于存储Java类的元数据、常量池、Intern字符串等。在JDK8之后,就将老年代移除,而引入元数据区的概念。

第五、Vritual空间。前面说过,可以使用Xms与Xmx来指定堆的最小与最大空间。如果Xms小于Xmx,堆的大小不会直接扩展到上限,而是留着一部分等待内存需求不断增长时,再分配给新生代。Vritual空间便是这部分保留的内存区域。

Java堆内的内存结构大体为:
技术图片

出处:https://mp.weixin.qq.com/s/mehFhIR2ne3Tnl7RlBNuhA

以上是关于堆内存结构是怎么样的?的主要内容,如果未能解决你的问题,请参考以下文章

数据结构和内存中堆和栈的区别

JVM的内存结构里的那个堆和栈,和数据结构里的堆和栈是一个东西吗?

C 语言结构体 ( 结构体 数组 作为函数参数 | 数组 在 堆内存创建 )

C语言中结构体在内存中的存储方式?

Elixir 进程和没有共享堆内存

JVM堆体系结构及其内存调优