Java 内存结构备忘录

基于Java+ Java Swing Mysql实现的桌面通讯录备忘录系统设计与实现 由Java swing MySQL实现的一款桌面通讯录备忘录系统,主要实现的功能有:通讯录分类管理、通讯录联系人管理、备忘录分类管理、备忘录管理、用户管理等,系统界面设计比较友好,功能也相对完善 阅读详情

本文详细描述了 Java 堆内存模型,垃圾回收算法以及处理内存泄露的最佳方案,并辅之以图表,希望能对理解 Java 内存结构有所帮助。原文作者 Sumith Puri,本文系 OneAPM 工程师编译整理。

下图展示了 Java 堆内存模型,以及运行在 Java 虚拟机中任意 Java 应用的 PermGen (内存永久保存区域),下面的比率展示了 JVM 各代类型允许的内存大小分配情况,所有的数据均适用于 Java 1.7 及以下版本。该图也被称为 Java 内存模型的“管理区(Managed Area)”。

Java 内存结构(Java 内存模型)

这里写图片描述

除此之外,还有一块堆栈区(Stack Area),可通过 -Xss 选项进行配置。该区域存储了所有线程的堆引用、本地引用、程序计数器寄存器、代码缓存以及本地变量。该区域也称为内存模型的本地区(Native Area)。

Java 内存模型(结构)的管理区

[Young Generation/Nursery] 伊甸园区(Eden Space)

所有新对象都首先在 Eden Space 创建。一旦该区达到由 JVM 设定的任意阈值,新生代垃圾回收机制(Minor GC)就会启动。它会首先清除所有的非引用对象,并将引用对象从 ‘eden’ 与 ‘from’ 区移至 ‘to’ 幸存者区。垃圾回收一结束,’from’ 与 ‘to’ 的角色(名字)就会对换。

[Young Generation/Nursery] 幸存者 1 区 (From)

这是幸存者区的一部分。或者视为幸存者区中的一个角色。这儿就是之前垃圾回收中的 ‘to’ 角色。

[Young Generation/Nursery] 幸存者 2 区 (To)

这也是幸存者区的一部分。也可以视为幸存者区中的一个角色。垃圾回收过程中的所有引用对象都会从 ‘from’ 与 ‘eden’ 区移至此处。

[Old Generation] 年老代区(Tenured)

根据阈值限定的不同,对象们会从 ‘to’ 幸存者区移至年老代区。你可以使用 -XX:+PrintTenuringDistribution 检查阈值,该指令会按照年龄显示对象(占用的字节空间)。年龄是指对象在幸存者区内移动的次数。

其他重要的标记还有 -XX:InitialTenuringThreshold、-XX:MaxTenuringThreshold 与 -XX:TargetSurvivorRatio ,这些标记能帮你实现最佳的年老代区与幸存者区使用方案。

通过设置 -XX:InitialTenuringThreshold 与 -XX:MaxTenuringThreshold,可以指定年龄的最初值与最大值,而幸存者区 (To) 的使用率则由 -XX:+NeverTenure 与 -XX:+AlwaysTenure 决定。前者是指永远不将对象存储到年老代区,而后者恰恰相反,总是将对象存储到年老代区。

此处进行的垃圾回收是年老代垃圾回收(Major GC)。当堆空间已满或者年老代区占满时,就会触发 Major GC。此时,通常会由一个“停止一切(Stop-the-World)”事件或线程执行垃圾回收。此外,还有另一种称为全垃圾回收(Full GC)的垃圾回收机制,会涉及诸如永久内存区域。

与整体堆内存相关的另两个重要且有趣的标记是 -XX:SurvivorRatio 与 -XX:NewRatio,前者指定伊甸园区相对幸存者区的比率,后者指定年老代区相对新生代区的比率。

[Permanent Generation] 永久代区(Permgen space)

永久代区(Permgen)用于存储以下信息:常量池 (内存池),字段与方法数据及代码。

垃圾回收算法

串行 GC(Serial GC) (-XX:UseSerialGC): 针对年轻代与年老代的垃圾回收

该算法使用简单的“标记-清扫-压缩(mark-sweep-compact)”循环清理年轻代与年老代,适合内存占用较低、CPU 使用量较少的客户端系统。

并行 GC(Parallel GC) (-XX:UseParallelGC): 针对年轻代与年老代的垃圾回收

该算法使用 N 个线程(N 的值可以通过 * -XX:ParallelGCThreads=N* 设定,N 同时代表垃圾回收占用的 CPU 内核数)。其中,年轻代垃圾回收会使用 N 个线程,而年老代只用一个线程。

并行 Old GC (-XX:UseParallelOldGC): 针对年轻代与年老代的垃圾回收

该算法对年轻代与年老代均使用 N 个线程,其他方面与并行 GC 完全一致。

并发 Mark and Sweep GC (-XX:ConcMarkSweepGC): 针对年老代的垃圾回收

顾名思义,CMS GC 会最小化垃圾回收所需的停顿时间。该算法最适于创建高响应度的应用,且只作用于年老代。它会创建多条垃圾回收的线程,与应用线程同时工作。垃圾回收的线程数量可以使用 -XX:ParallelCMSThreads=n 标记指定。

G1 GC (-XX:UseG1GC): 针对年轻代与年老代的垃圾回收 (将堆内存等分为大小相同的区块)

这是一种并行、并发、不断压缩的低停顿垃圾回收器。G1 是在 Java 7 中引入以取代 CMS GC 的,它会先将堆内存分为多个大小相等的区块,继而执行垃圾回收。通常,从活动数据最少的区块开始,因此以垃圾为先。

最常见的内存溢出问题

所有 Java 程序员都应该知道的最常见的内存溢出问题:

  • Exception in thread “main”: java.lang.OutOfMemoryError: Java heap space( Java 堆内存)。这并不一定意味着内存泄露,也可能是分配的堆内存空间太小。此外,在运行时间较长的应用中,也可能是因为一个无意识的引用被指向堆对象(内存泄露)。即便是应用本身调用的 APIs,也可能保存着指向无依据对象的引用。而且,在大量使用终结器的应用中,对象们有时可能正排在终结队列中。当这样的应用创建高优先级的线程时,会导致越来越多的对象排在终结队列中,最终导致内存溢出。

  • Exception in thread “main”: java.lang.OutOfMemoryError: PermGen space(永久存储空间)。如果加载了很多类与方法,或者创建了很多字符串常量,特别是使用 intern() 方法进行创建(从 JDK 7 开始,interned 字符串就不再存储在 PermGen 中),这类错误就会出现。当出现这类错误时,打印的堆栈跟踪附近可能会出现如下文本:ClassLoader.defineClass。

  • Exception in thread “main”: java.lang.OutOfMemoryError: Requested array size exceeds VM limit (请求的数组大小超出 VM 限制)。当请求的数组大小超过可用的堆空间时,这类报错就会出现。这类错误通常归咎于编程错误,在运行时请求了极大的数组大小。
  • Exception in thread “main”: java.lang.OutOfMemoryError:
    request <s> bytes for <r>,交换空间溢出?这是内存泄露最常见的根源。通常,当操作系统没有足够的交换空间,或另一个进程占用了系统中的所有可用内存,就会导致内存泄露。简而言之,由于空间用尽,堆内存无法提供所请求的空间大小。该信息中的 ‘s’ 代表失败的请求所需的内存大小(以字节为单位),而 ‘r’ 代表内存请求的原因。在大多数情况下,此处的 ‘r’ 是报告分配失败的源模块,有时也会是具体的原因。

  • Exception in thread “main”: java.lang.OutOfMemoryError: (Native method)(<原因><堆栈跟踪><本地方法>)。该报错意味着一个本地方法遇到内存分配失败。问题的根源在于 Java Native Interface(Java 本地接口) 中存在的错误,而非 JVM 中运行的代码错误。若是本地代码不检查内存分配错误,应由会直接崩溃,而不会出现内存溢出。

内存泄露的定义

你可以将内存泄露看做一种疾病,而内存溢出错误为一种征兆。但不是所有的内存溢出错误都意味着内存泄露,不是所有的内存泄露都以内存溢出为征兆。

维基百科的定义:在计算机科学中,内存泄露是一种以如下方式发生的资源泄露——计算机程序错误地分配内存,导致不再需要的内存得不到释放。在面向对象的编程语言中,一个对象若存储在内存中,却无法由运行的代码获取,即为内存泄露。

Java 中常用的内存泄露定义

当不再需要的对象引用仍旧多余地予以保存,即为内存泄露。

在 Java 中,内存泄露是指对象已不再使用,但垃圾回收未能将他们视做不使用对象予以回收。

当程序不再使用某个对象,但在一些无法触及的位置该对象仍旧被引用,即为内存泄露。也因此,垃圾回收器无法删除它。该对象占用的内存空间无法释放,程序所需的总内存就会增加。久而久之,应用的性能就会下降,JVM 可能会耗尽所有内存。

在某种程度上,当无法再给年老区分配内存时,内存泄露就会发生。

内存泄露最常见的一些情况:
- ThreadLocal 变量
- 循环与复杂的双向引用
- JNI 内存泄露
- 可变的静态域(最为常见)

我建议结合使用 Visual VM 与 JDK,对内存泄露问题进行调试。

常见的内存泄露调试方法

  1. NetBeans 分析器
  2. 使用 jhat Utility
  3. 创建 Heap Dump
  4. 获取当下运行进程的堆内存柱状图
  5. 获取内存溢出错误的堆内存柱状图
  6. 监控在等待终结的对象数量
  7. 第三方内存调试器

调试内存泄露问题的常用策略或步骤:

  • 确认征兆
  • 启用详细的垃圾回收机制(verbose GC)
  • 启用性能分析
  • 分析堆栈跟踪

原文地址:https://dzone.com/articles/java-memory-architecture-model-garbage-collection

OneAPM for Java 能够深入到所有 Java 应用内部完成应用性能管理和监控,包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。想阅读更多技术文章,请访问 OneAPM 官方博客。

Research Proposal:自动驾驶 行人运动预测 Research Proposal about Pedestrian/Cyclist Motion Prediction for Self-Driving Vehicles   If I can be provided with the opportunity to conduct PhD research in pedestrian/cyclist motion prediction for... 阅读详情

相关推荐

从零开始:用LabVIEW和ModbusTCP协议,像搭积木一样连接Delta PLC

本文详细介绍了如何利用LabVIEW的图形化编程环境和ModbusTCP工业协议,快速连接Delta PLC实现数据通信。通过模块化配置和实战案例,指导读者无需编写复杂代码即可完成寄存器读取、多数据类型处理及系统监控,显著提升工业自动化项目的开发效率与部署速度。

n8m7b6v5c4的博客 693

JVM参数详解以及配置调优

http://www.cjsdn.net/post/view?bid=1&id=197954 

戴小丹的专栏 504

大模型驱动时序量化因子自动优化:从WorldQuant回测到实战策略

本文探讨了如何利用大模型驱动时序量化因子的自动优化,构建从创意生成到实战验证的完整流程。通过结合WorldQuant回测平台,搭建自动化流水线,详细拆解了因子生成、回测验证与迭代优化的核心模块。文章分享了从初版实现到进阶优化的实践经验,并指出提示词工程与领域知识注入是关键,旨在实现人机智能协作,提升量化策略研发效率。

wdx012345的博客 803

AXIS java heap 回收方式

为了减少在内存回收过程中,机器等待的时间,AXIS中有如下两种内存回收方式: 1.Concurrent garbage collection  2.Generational garbage collectionThe对于 concurrent方式,它可以在回收内存的某些操作时候不停时JVM的运行,以减少内存回收的等待时间 对于Generational比较大的heap,问题可能会

deadguy15的专栏 505

Win10系统VS2019+Cmake+qhull_8.0.0环境配置

1 qhull 1.1 简要介绍 qhull是一个强大的计算几何库,可以用于计算高维的convex hull, Delaunay triangulation, Voronoi diagram等。 1.2 依赖库 qhull不依赖其他库。 1.3 源码包下载 qhull源码地址:github:https://github.com/qhull/qhull.git 2 Cmake构建项目 2.1 路径 源代码路径:D:/ThirdParty/qhull/qhull_8.0.0构建项目路径:D:/Thi.

wangchenxue的博客 2489

别再为SCI论文配图发愁了!手把手教你用PS+AI搞定从数据图到模式图的全流程

本文详细解析了如何利用Photoshop(PS)和Illustrator(AI)高效完成SCI论文配图的全流程,涵盖数据可视化、模式图设计及期刊适配性输出。通过实战案例,帮助科研人员掌握位图与矢量图的处理技巧,提升论文配图质量,满足不同期刊的出版要求。

weixin_28630185的博客 381

Robocup 仿真2D 学习笔记(二) 球队代码编译和上场

环境的一些问题 最近在使用rcssserver 和 rcssmonitor时可能会遇到./configure失败的问题,可以检查一下文件夹是否有makefile文件,如果是编译后的包直接sudo make install,如果还不行,还可以源码下载编译 rcssserver: https://sourceforge.net/projects/sserver/files/rcssserver/...

markchalse的博客 6014

JVM7、8详解及优化

1. JVM堆内存划分1.1 JDK7及以前的版本其中最上一层是Nursery内存,一个对象被创建以后首先被放到Nursery中的Eden内 存中,如果存活期超两个Survivor之后就会被转移到长时内存中(Old Generation)中。永久内存中存放着对象的方法、变量等元数据信息。通过如果永久内存不够,就会得到如下错误:Java.lang.OutOfMemoryError: PermGen1

梓纾的专栏 2万+

[数据转换]将NetCDF(NC)文件转换成单个GeoTIFF文件

有时候要提取tif格式数据中的气象数据,但从气象网站上下载的却是NC格式的文件。这就需要我们将NC格式的文件转换成TIF格式的文件。

G_sea_young的博客 1004

Qt C++ 实现一个完整的扫雷

mineCountLabel = new QLabel(QString("地雷: %1").arg(remainingMines, 3, 10, QChar('0')), this);mineCountLabel->setText(QString("地雷: %1").arg(remainingMines, 3, 10, QChar('0')));timeLabel->setText(QString("时间: %1").arg(gameTime, 3, 10, QChar('0')));" : "游戏失败!

寒寒豆豆软件公司的博客 107

java eden space_Java 内存结构备忘录

本文详细描述了 Java 堆内存模型,垃圾回收算法以及处理内存泄露的最佳方案,并辅之以图表,希望能对理解 Java 内存结构有所帮助。原文作者 Sumith Puri,本文系 OneAPM 工程师编译整理。下图展示了 Java 堆内存模型,以及运行在 Java 虚拟机中任意 Java 应用的 PermGen (内存永久保存区域),下面的比率展示了 JVM 各代类型允许的内存大小分配情况,所有的数...

weixin_42306812的博客 468

20、啁啾脉冲光纤放大器:原理、设计与仿真

本文详细介绍了啁啾脉冲光纤放大器(FCPA)的原理、设计与仿真过程。内容涵盖CPA技术的基本原理、光纤基CPA系统的组成、Tm掺杂光纤放大器的工作机制、全光纤脉冲展宽器的设计以及仿真分析。通过MATLAB仿真展示了脉冲在光纤中的展宽与放大过程,并讨论了如何优化系统以减少非线性失真、控制峰值功率并提高整体性能。文章还总结了系统优化的关键策略,并展望了未来的发展方向。

v4w5x6的博客 317

【HeadFirst系列之HeadFirstJava】第17天之备忘录模式全解析:如何优雅地实现撤销、回滚与存档?(附 Java 实战)

假设我们要在一个文本编辑器中实现“撤销”功能,最简单的方法是。本篇文章基于《Head First 设计模式》,深入剖析。,可以保存多个状态,并支持**撤销(Undo)**功能。备忘录模式(Memento Pattern)用于。如果不加控制地使用对象副本来保存状态,不仅。,帮助你掌握这一重要设计模式!:如果状态变化频繁,存储和恢复。:如果对象状态过大,存储多个。在软件开发中,我们经常需要。:可以轻松地恢复历史状态。可能导致内存占用过高。的操作可能会影响性能。

工一木子 1022

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java 可扩展状态系统设计:备忘录模式的工程化实践与架构演进

备忘录模式(Memento Pattern)是一种行为型设计模式,其核心思想是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。其本质是通过封装状态对象实现历史状态的管理,避免直接暴露对象内部细节。备忘录模式通过巧妙的封装设计,在不破坏对象封装性的前提下实现了灵活的状态管理。它不仅解决了撤销操作等具体问题,更体现了 "将变化封装" 的设计思想。

qq_20294455的博客 1304

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

设计模式系列文章(基础篇第23篇):备忘录模式——保存对象状态,实现可逆操作

1. 核心定义备忘录模式(Memento Pattern):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。备忘录模式的核心是封装状态备份与恢复,不暴露对象内部细节。通俗理解:备忘录模式就像我们生活中的“笔记本”和“记账员”。假设你是一名作家(原发器),正在写一篇文章,你会定期将当前的写作内容(内部状态)抄写到笔记本上(备忘录),并交给助手(负责人)保管。

qq_29757467的博客 319

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

23种设计模式一备忘录模式

备忘录模式是一种行为型设计模式,用于在不破坏封装性的前提下捕获和恢复对象状态。它包含三个核心角色:发起人(保存/恢复状态)、备忘录(存储状态)和管理者(保存备忘录)。该模式适用于文本编辑器撤销、游戏存档等场景,通过状态管理实现对象的历史状态恢复。示例展示了文本编辑器如何利用备忘录模式实现撤销功能,包括保存编辑状态和恢复历史记录。掌握该模式有助于开发可维护的状态管理系统。

J_liaty的博客 843

设计模式系列文章(基础篇第39篇):备忘录模式——保存对象状态,实现回溯恢复

// 管理者:撤销管理器,负责管理所有备忘录 public class UndoManager { // 使用栈存储备忘录(先进后出,支持撤销到上一步) private Stack mementoStack = new Stack<>(); // 保存当前状态:接收原发器的备忘录并存储 public void saveState(Memento memento) { mementoStack.push(memento); } // 撤销到上一步:从栈中弹出最新的备忘录并返回 public Memento u

qq_29757467的博客 383

设计模式之十七—备忘录模式:让对象拥有“时光倒流”的能力

备忘录模式是一种行为型设计模式,它允许我们保存和恢复一个对象的内部状态,而不会暴露其实现细节。发起人(Originator):需要被保存状态的对象。它负责创建备忘录,以及使用备忘录恢复自身状态。备忘录(Memento):用于存储发起人内部状态的对象。它通常只允许发起人访问其内部数据,对其他对象屏蔽细节。负责人(Caretaker):负责保存备忘录,但不能对备忘录内容进行操作或检查。它可以在需要时将备忘录传递给发起人进行恢复。通过这种设计,发起人的封装性得到了保护,状态的保存和恢复职责被清晰地分离。

技术交流,一起进步 612

Java常用的设计模式

Java设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

xxxzzzqqq_的博客 165

【设计模式】用Java实现备忘录模式

备忘录模式(Memento Pattern)是一种行为设计模式,它允许将对象的内部状态保存在一个备忘录对象中,并在需要时恢复对象的状态,而不破坏对象的封装性。备忘录模式的核心是备忘录(Memento)角色,它用于存储对象的内部状态,并提供对状态的访问方法。原发器(Originator)角色负责创建备忘录并将自身的状态保存到备忘录中。管理者(Caretaker)角色负责存储和恢复备忘录,但是它不能访问备忘录的内部状态。当需要保存和恢复对象的内部状态,并且希望封装状态的具体实现细节时,可以使用备忘录模式。

分享Java硬核干货 9863

java备忘录系统的专业设计

JAVA中的备忘录模式实例教程原文链接  作者:Pankaj Kumar 译者:f0tlo &lt;1357654289@qq.com&gt;备忘录模式是一种行为模式。备忘录模式用于保存对象当前状态,并且在之后可以再次使用此状态。备忘录模式实现的方式需要保证,被保存的对象状态不能被对象从外部访问,目的为了被保存的这些对象状态的完整性。备忘录模式通过两个对象实现:Originator以及Careta...

qq_42528398的博客 775

深入浅出设计模式 - 备忘录模式

深入浅出设计模式 - 备忘录模式

激流丶的博客 2983
上一篇: 为什么选择 Java 8 ?
下一篇: Mac下使用ssh、scp
Viking_bird
博客等级 码龄11年 92粉丝 183原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值