0

0

Java内存以及GC

高洛峰

高洛峰

发布时间:2016-10-20 10:45:57

|

1844人浏览过

|

来源于php中文网

原创

java内存区域与内存溢出

Java虚拟机中的内存分配图:

1.jpg

各个区域的特性总结如下表:

1.png

立即学习Java免费学习笔记(深入)”;

补充说明:

当多线程情形下,可能多个线程要在堆上分配内存,那么可能出现内存分配的同步问题,解决方案有两个,一个就是同步内存分配动作;另一个就是采用TLAB,即在Java堆中针对每个线程先预先分配一小块线程私有的本地线程分配缓冲。这样当线程需要分配内存时就在自己的TLAB上进行,从而避免同步的开销。但是当TLAB分配满重新分配TLAB时仍需要同步;

判断一个类是否属于无用的类,“可以”被回收的条件为:1 该类所有的实例都已经被回收;2 加载该类的ClassLoader已经被回收; 3 该类对于的java.lang.Class对象没有在任何地方被引用。注意,只是可以,而不是要被回收。

内存分配方式:虚拟机使用哪种方式由内存是否规整决定,而内存是否规整则由回收算法决定。

指针碰撞:假设所有已经被分配的内存放在一边,而空闲的放在另外一边,二者中间则用一个指针来作为分界点,当需要分配内存时只需要移动该指针即可,这样的方式称为指针碰撞。使用此方法的有Serial、ParNew等带Compact的回收器

空闲列表:虚拟机中已分配的内存和空闲的内存并不规整,处于相互交错的情形,那么就需要通过维护一个列表来表示哪些内存是可用,当需要分配内存时则需要通过查询列表来查找可用大小的内存。这样的方式称为空闲列表。使用此方法的有CMS等这种基于Mark-Sweep算法的回收器

对象在HotSpot虚拟机中的内存布局如下表所示:

1.png

在Java规范中,对于reference类型只规定了一个指向对象的引用,但没有规定通过何种方式去访问引用的数据。因此对于不同的虚拟机也有不同的访问方式,主要有两种方式:

使用句柄:在Java堆中划出一块区域作为句柄池来存储句柄,一个句柄包括对象实例数据的指针以及对象数据类型的指针,reference中存储的就是对象的句柄的地址。reference通过句柄来间接访问对象。其好处在于:当对象移动时,只需要改动矩形中的指针即可,而相应的reference则不需要做变动;

直接访问:reference存储的是对象地址,通过reference就可以直接访问数据。Java对中的数据对象中含有到对象数据类型的指针,比如上面提到的类型指针。此种方式的好处就是访问速度快,相比使用句柄的方式而言少了一次指针定位的开销。HotSpotVM使用的是此种方式。

两种使用方式的图示说明如下图:图片来源 http://www.th7.cn/Program/java/201604/846729.shtml

1.jpg

垃圾回收算法

判断一个对象是否死去,不可能再被用的算法有两种:

引用计数算法:对于一个对象,其被引用的次数增加一次,则计数加1,当引用失效的时候就减1.当其计数为0时,则认为该对象死去。该算法的特点是效率高,但是很难解决对象之间的相互引用问题。使用此算法的有MS的COM技术以及Python等

可达性分析算法:该算法的核心就是从GC Roots开始,检测所引用的所有对象。若一个对象到GC Roots之间没有任何引用链,那么认为该对象已死。使用此算法的有Java、C#等。

可以作为GC Roots的对象有:

虚拟机栈(栈帧中的本地变量表)中引用的对象

百灵大模型
百灵大模型

蚂蚁集团自研的多模态AI大模型系列

下载

方法区中类静态属性引用的对象

方法区中常量引用的对象

Native方法中引用的对象

在Java中有四种引用强度:

强引用:强引用永远不会被垃圾回收器回收

软引用:系统提供SoftReference类来表示,表示还有但是非必须的对象。其回收时机在于把若引用对象回收完之后内存还不够,则回收此类引用,若还不够,则OOM

弱引用:通过WeakReference类来表示,此类引用只能生存到下一次垃圾回收之前。当垃圾收集器工作时,无论当前内存是否足够都会回收掉只被弱引用关联的对象。即只要发生了GC,弱引用必定被回收。其与已经没有到GC Roots的引用链的区别在于:还是可以通过弱引用来访问这些对象的,但是没有引用链的对象则永远不可能再被访问到了。

虚引用:通过PhantomReference来实现,其对对象的生存时间没有任何影响,其存在的意义在于能在被虚引用引用的对象被回收的时候收到一个系统通知。

系统的GC工作流程如下图所示,总的来说,一个对象被回收可能会经过两次标记过程,并且可能在finalize方法中拯救自己以避免被回收。

1.png

 几种典型的垃圾回收算法:

1.png

HotSpot VM中的垃圾回收算法的具体实现细节:为了结果的准确,GC在扫描时是需要冻结所有线程的。目前主流的Java虚拟采取的都是准确式GC,即系统知道每个内存位置的数据到底是一个什么数据类型,以HotSpot为例,它采取的是一个叫做OopMap的数据结构来实现这样的映射记录。有了这样的信息,虚拟机就直接知道哪些地方存放着对象的引用,从而避免了对内存挨个的检查,加快了GC扫描的速度。程序的每条指令都可能导致引用关系或者内存数据的变化,即会导致OopMap的变化,这样的话,如果给每个指令都生成一个对应的OopMap数据那么是相当占用空间的,于是提出了安全点的概念(SafePoint),即只有当每个线程都运行到线程对应的安全点时才进行GC扫描,从而也只要给安全点上的指令生成OopMap即可,这样就减少了OopMap的数量。而安全点的选取要考虑到GC频率与系统性能的综合影响,一般选取方法调用、循环跳转、异常跳转等“具有让程序长时间运行的特征”的点。为了让线程都跑到安全点停顿下来以进行GC扫描,有抢先式中断和主动式中断两种方式。这里又有另外一个问题,如果遇到一个比如处于Sleep状态的线程,那么它是不会走动的,如果它恰好不是在一个安全点Sleep,那么意味着它永远不会走到安全点来,所以又提出了安全区域(SafeRegion)的概念。即在这个区域内的点都是安全点。线程进入安全点之后会标志自己进入了安全区域,且必须等GC执行完了才会离开安全区域。

 

 各个垃圾回收器:

1.png

几条最普遍的内存分配规则:

对象优先分配在Eden区:当Eden区内存不够的时候,系统将发起一次速度较快的Minor GC

大对象直接进入老年代:对于较长的数组以及字符串等大对象,直接把他们分配在老年代区。因此,对于那种生命周期较短的大对象,很容引起GC,应该尽量避免。

长期存活的对象将进入老年代:一个若在Survivor区经历多次Minor GC还存活,默认15次,则将被移入老年代区。

动态对象年龄判定:此条是结合上一条的,要是Survivor中相同年龄的所有对象的大小和超过Survivor的一半,那么年龄大于或者等于该年龄的对象将移入老年代区,无需等到15次

空间分配担保:针对新生代的复制收集算法。若参数容许,当执行Minor GC之后,若存活的对象无法全部放在Survivor中,那么将把多的对象直接放入老年代区。若老年代也没足够的空间,那么将发生Full GC以获得更多空间

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Nginx跨平台安装实操指南:Windows、macOS与Linux环境快速搭建
Nginx跨平台安装实操指南:Windows、macOS与Linux环境快速搭建

本指南详解Nginx在Windows、macOS及Linux系统的安装全流程。涵盖官方包解压、Homebrew一键部署、APT/YUM源配置及Docker容器化方案。无论新手或开发者,均可快速搭建运行环境,掌握跨平台核心指令,为后续配置与调优奠定坚实基础。

9

2026.03.16

chatgpt使用指南
chatgpt使用指南

本专题整合了chatgpt使用教程、新手使用说明等等相关内容,阅读专题下面的文章了解更多详细内容。

22

2026.03.16

chatgpt官网入口地址合集
chatgpt官网入口地址合集

本专题整合了chatgpt官网入口地址、使用教程等内容,阅读专题下面的文章了解更多详细内容。

52

2026.03.16

minimax入口地址汇总
minimax入口地址汇总

本专题整合了minimax相关入口合集,阅读专题下面的文章了解更多详细地址。

21

2026.03.16

C++多线程并发控制与线程安全设计实践
C++多线程并发控制与线程安全设计实践

本专题围绕 C++ 在高性能系统开发中的并发控制技术展开,系统讲解多线程编程模型与线程安全设计方法。内容包括互斥锁、读写锁、条件变量、原子操作以及线程池实现机制,同时结合实际案例分析并发竞争、死锁避免与性能优化策略。通过实践讲解,帮助开发者掌握构建稳定高效并发系统的关键技术。

10

2026.03.16

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

116

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

142

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

412

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

65

2026.03.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
php-src源码分析探索
php-src源码分析探索

共6课时 | 0.5万人学习

golang和swoole核心底层分析
golang和swoole核心底层分析

共3课时 | 0.2万人学习

Redis中文开发手册
Redis中文开发手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号