深入理解Java之JVM堆内存分配

简介:

Java堆是被所有线程共享的一块内存区域,所有对象和数组都在堆上进行内存分配。为了进行高效的垃圾回收,虚拟机把堆内存划分成新生代、老年代和永久代(1.8中无永久代,使用metaspace实现)三块区域。
这里写图片描述

Java把内存分成两种:栈内存和堆内存。关于堆内存和栈内存的区别与联系。简单的来讲,堆内存用于存放由new创建的对象和数组,在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。而栈内存由使用的人向系统申请,申请人进行管理。

堆内存初始化

Java中分配堆内存是自动初始化的,其入口位于Universe::initialize_heap方法中,相关代码如下:
这里写图片描述

其中UseParallelGC、UseG1GC、UseConcMarkSweepGC都可以通过启动参数进行设置,整个初始化过程分成三步:
1、初始化GC策略;
2、初始化分代生成器;
3、初始化Java堆管理器;

GC策略初始化

HotSpot的GC策略实现如下:
这里写图片描述

其中MarkSweepPolicy是基于标记-清除思想的GC策略,如果虚拟机启动参数没有指定GC算法,则使用默认使用UseSerialGC,以ASConcurrentMarkSweepPolicy策略为例,对GC策略的初始化过程进行分析:
这里写图片描述

调用父类ConcurrentMarkSweepPolicy构造方法,其中initialize_all定义在GenCollectorPolicy中,相关代码如下:
这里写图片描述

initialize_flags

负责对新生代、老年代以及永久代设置的内存大小进行调整。

调整永久代

由CollectorPolicy::initialize_flags实现,永久代的初始值默认为4M,最大值为64M,可以通过参数-XX:PermSize和-XX:MaxPermSize进行重新设置。代码如下:

这里写图片描述

调整新生代

由GenCollectorPolicy::initialize_flags实现:
1、新生代的初始值NewSize默认为1M,最大值需要设置,可以通过参数-XX:NewSize和-XX:MaxNewSize或-Xmn进行设置;
2、NewRatio为老年代与新生代的大小比值,默认为2;
3、SurvivorRatio为新生代中Eden和Survivor的大小比值,默认为8;

这里写图片描述

调整老年代

由TwoGenerationCollectorPolicy::initialize_flags实现
1、老年代的初始值OldSize默认为4M,可以通过参数-XX:OldSize进行设置;
2、最大堆大小MaxHeapSize默认为96M,可以通过参数-Xmx进行设置;
3、如果设置的新生代和老年代的内存容量大于MaxHeapSize,则重新设置MaxHeapSize;

这里写图片描述

initialize_size_info

设置新生代、老年代以及永久代的容量,包括初始值、最小值和最大值

设置堆容量

其中InitialHeapSize和Arguments::min_heap_size()可以通过参数-Xms进行设置。
1、设置初始堆容量_initial_heap_byte_size;
2、设置最小堆容量_min_heap_byte_size;
3、设置最大堆容量_max_heap_byte_size;

相关代码如下:
这里写图片描述

设置新生代

这里写图片描述

1、如果MaxNewSize重新设置过,即设置-Xmn参数,则根据不同情况设置max_new_size;
2、否则通过scale_by_NewRatio_aligned方法根据NewRatio和_max_heap_byte_size重新计算max_new_size值,其中NewRatio默认为2,表示新生代的大小占整个堆的1/3;

这里写图片描述

3、如果最大堆_max_heap_byte_size等于最小堆_min_heap_byte_size,则设置新生代的初始值、最小值和最大值为max_new_size,否则执行下一步。

这里写图片描述

4、如果NewSize重新设置过,即设置了-Xmn参数,则使用NewSize设置_min_gen0_size,否则使用scale_by_NewRatio_aligned方法重新计算新生代最小值和初始值,实现如下:

这里写图片描述

设置老年代

1、如果参数没有设置OldSize,则使用min_heap_byte_size() - min_gen0_size(),即最小堆大小和新生代最小值之差设置老年代最小值,初始值类似;
2、否则根据设置的OldSize,通过adjust_gen0_sizes方法重新设置新生代的最小值和初始值;

初始化分代生成器

分代生成器保存了各个内存代的初始值和最大值,新生代和老年代通过GenerationSpec实现,永久代通过PermanentGenerationSpec实现。

GenerationSpec

这里写图片描述

每个生成器GenerationSpec实例保存当前分代的GC算法、内存的初始值和最大值。

PermanentGenerationSpec

这里写图片描述

除了GenerationSpec实例中的数据,如果设置UseSharedSpaces和DumpSharedSpaces,还需要保存额外的数据。ConcurrentMarkSweepPolicy::initialize_generations方法实现了分代生成器的初始化,实现如下:
这里写图片描述

初始化Java堆管理器

GenCollectedHeap是整个Java堆的管理器,负责Java对象的内存分配和垃圾对象的回收,通过initialize方法进行初始化,相关代码如下:

这里写图片描述

1、通过GC策略的number_of_generations方法获取分代数量,如果使用ASConcurrentMarkSweepPolicy,默认分代数为2;
2、通过align方法对齐生成器的初始值和最大值;

这里写图片描述

3、通过allocate为堆申请空间;
这里写图片描述

4、通过分代生成器的init方法为对应的分代分配内存空间;
这里写图片描述

5、如果当前的GC策略为ConcurrentMarkSweepPolicy,则通过create_cms_collector创建GC线程。

到此,JVM堆内存的完整分配流程就分析完了。

目录
相关文章
|
9月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
1089 3
|
10月前
|
存储 缓存 Java
Java数组全解析:一维、多维与内存模型
本文深入解析Java数组的内存布局与操作技巧,涵盖一维及多维数组的声明、初始化、内存模型,以及数组常见陷阱和性能优化。通过图文结合的方式帮助开发者彻底理解数组本质,并提供Arrays工具类的实用方法与面试高频问题解析,助你掌握数组核心知识,避免常见错误。
|
8月前
|
Java 大数据 Go
从混沌到秩序:Java共享内存模型如何通过显式约束驯服并发?
并发编程旨在混乱中建立秩序。本文对比Java共享内存模型与Golang消息传递模型,剖析显式同步与隐式因果的哲学差异,揭示happens-before等机制如何保障内存可见性与数据一致性,展现两大范式的深层分野。(238字)
253 4
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
384 0
|
8月前
|
存储 缓存 Java
【深入浅出】揭秘Java内存模型(JMM):并发编程的基石
本文深入解析Java内存模型(JMM),揭示synchronized与volatile的底层原理,剖析主内存与工作内存、可见性、有序性等核心概念,助你理解并发编程三大难题及Happens-Before、内存屏障等解决方案,掌握多线程编程基石。
|
9月前
|
缓存 监控 Kubernetes
Java虚拟机内存溢出(Java Heap Space)问题处理方案
综上所述, 解决Java Heap Space溢出需从多角度综合施策; 包括但不限于配置调整、代码审查与优化以及系统设计层面改进; 同样也不能忽视运行期监控与预警设置之重要性; 及早发现潜在风险点并采取相应补救手段至关重要.
1030 17
|
10月前
|
监控 Kubernetes Java
最新技术栈驱动的 Java 绿色计算与性能优化实操指南涵盖内存优化与能效提升实战技巧
本文介绍了基于Java 24+技术栈的绿色计算与性能优化实操指南。主要内容包括:1)JVM调优,如分代ZGC配置和结构化并发优化;2)代码级优化,包括向量API加速数据处理和零拷贝I/O;3)容器化环境优化,如K8s资源匹配和节能模式配置;4)监控分析工具使用。通过实践表明,这些优化能显著提升性能(响应时间降低40-60%)同时降低资源消耗(内存减少30-50%,CPU降低20-40%)和能耗(服务器功耗减少15-35%)。建议采用渐进式优化策略。
573 2
|
Java 物联网 数据处理
Java Solon v3.2.0 史上最强性能优化版本发布 并发能力提升 700% 内存占用节省 50%
Java Solon v3.2.0 是一款性能卓越的后端开发框架,新版本并发性能提升700%,内存占用节省50%。本文将从核心特性(如事件驱动模型与内存优化)、技术方案示例(Web应用搭建与数据库集成)到实际应用案例(电商平台与物联网平台)全面解析其优势与使用方法。通过简单代码示例和真实场景展示,帮助开发者快速掌握并应用于项目中,大幅提升系统性能与资源利用率。
333 6
Java Solon v3.2.0 史上最强性能优化版本发布 并发能力提升 700% 内存占用节省 50%
|
10月前
|
安全 Oracle Java
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
705 0
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡