JVM内存架构和GC算法基础

JVM内存管理(堆、栈和元空间)和不同垃圾收集算法概述

本文讨论了JDK8的基本概念以及使用堆和堆栈内存的向上内存管理。GC及其算法的基础知识。

内存管理的重要性

Java垃圾收集器不能确保堆内存完全空闲,而且对于开发人员来说,也不可能强制垃圾收集器在特定的时间运行。所以了解Java中的内存管理是如何工作的是很有帮助的。

了解内存管理有助于编写优化的内存高效代码,并有助于避免程序中任何与内存相关的问题,这些问题会导致应用程序变慢,并有助于避免以下错误StackOverFlowError和OutOfMemoryError.

栈存储器

Stack是一种线性数据结构,是Java为存储堆对象引用而进行的静态内存分配,也存储Java原语类型值。堆栈以后进先出(LIFO)的方式访问内存 订单和堆栈比堆快 记忆.

每个线程在内存中创建自己的堆栈,这反过来使堆栈内存线程安全。

Java中的方法只访问方法体中(方法范围内)堆栈内存中的对象。当方法执行完成时,该方法的相应块将从堆栈中清除。

在上面的程序中,我们可以看到当控件到达main方法时,将有一个args在堆栈中。然后当控件在下一行时,一个新的条目被添加到堆栈中。

当控件超出方法的范围时,引用将从堆栈中删除。

如果堆栈内存变满,JVM会抛出一个StackOverFlowError.

堆内存

堆用于JVM在运行时为Java对象动态分配内存。任何新对象都存储在堆中reference(example variables) 对象的存储在堆栈上。您可以在下面的示例中看到示例代码的变量是如何存储在堆和堆栈中的。

int age = 5;
String name = "Sherine";
List<String> subjectLst = new ArrayList<String>();
subjectLst.add("English");
subjectLst.add("Science");
List<String> finalLst;
finalLst = subjectLst;

下面是上述代码片段在堆中的内存分配。

堆内存可以分解成更小的部分,称为几代人,年轻的,年老的/终身的,  永久世代.

年轻一代

所有新对象都被分配到这个内存段中。年轻一代包括伊甸园 二幸存者空间。当伊甸园填满时,垃圾收集发生在年轻一代,这被称为次要GC来自年轻一代的被引用对象在次要GC期间被移动到幸存者空间#1,并且对象的年龄增加。

例如,在下图中,“对象1”和“对象2”将在第一次次要GC之后移动到幸存者空间#1,并且它们将具有指定的年龄。如果“对象1”在第一次小GC中幸存,则年龄为零。现在,如果“对象1”也在下一次次要GC中幸存,那么它将被移动到幸存者空间2,并且年龄将再次递增。

图1:伊甸园已满,在小垃圾收集之前

在第二次次要GC期间,驻留在幸存者空间#1中的对象(具有引用)将被移动到幸存者空间#2,并且年龄将递增(即,根据该示例,年龄将从0变到1)。所有未被引用的对象都将被删除。

图2:第一次小GC后

老一代

老一代是存储长寿对象(最老的对象)的地方。年轻一代对象有一个年龄上限或阈值。一旦一个对象达到了这个上限,那么这个对象就被转移到旧的或保留的代。

永久Gen

堆内存的这一部分用于存储运行时类和方法的元数据。这部分记忆已经完全从JDK 8中移除 由Java和替换为元空间概念。你仍然可以设置--XX:PermSize和-XX:MaxPermSize配置。但是,如果你在JDK 8或更高版本上运行该应用程序,你将在运行时收到警告。

元空间

这是引进的从JDK 8版本开始,这是一个可调整大小的存储器面积和从本机内存中分配。元空间保存类元数据,它不是一个连续的内存位置。

每当元空间达到为元空间分配的最大大小时,Java就会触发自动GC来释放元空间内存。

元空间选项包括-XX:MetaspaceSize=size和-XX:MaxMetaspaceSize=size

碎片帐集

Java程序编译并转换成字节码,在JVM (Java虚拟机)上运行。Java程序的对象是在该程序的专用堆内存上创建的。随着时间的推移,越来越多的对象被创建,一些对象(未引用的和范围缩小的)不再被程序所需要。垃圾收集是Java的一个进程,它执行自动内存管理,并通过删除未引用的对象来释放内存空间。

JVM包含了不同的垃圾收集算法。垃圾收集算法检查内存中的每个引用对象,其余的对象被认为是垃圾收集的。

GC算法的类型

下面是JVM可用的4种GC算法。

  • 并行GC
  • 串行GC
  • 并发标记和渗漏
  • G1垃圾第一

并行GC

专为多线程应用并在多处理器环境中很好地工作。但是它在垃圾收集期间冻结了所有的应用程序线程。对此的JVM选项是-XX:+UseParallelGC还有一个选项,您可以通过使用-XX:ParallelGCThreads=<NoOfThreads> .

串行GC

主要设计用于单线程环境。Liek并行GC,它也在垃圾收集期间冻结所有的应用程序线程。对此的JVM选项是-XX:+UseSerialGC.

并发标记和渗漏(CMS)

这是一个并发GC,旨在缩短GC暂停时间执行GC不需要停止正在运行的应用程序。这就是为什么这个过程比串行或并行GC慢的原因。它使用多线程进行垃圾收集,并且能够与垃圾收集器共享处理器资源。对此的JVM选项是-XX:+UseConcMarkSweepGC

G1垃圾收集器(G1GC)

这是另一个最有效的并发GC,是为内存量更大的多处理器环境设计的。对此的JVM选项是-XX:+UseG1GC

选择GC算法的参数

除非你对GC计时有一些特殊的要求,并且需要制定其他规范,否则最好让JVM自己选择GC算法。

如果你想要选择和配置GC算法,那么需要考虑一些参数,如堆大小、CPU内核数量、应用程序数据集容量、吞吐量、暂停时间、延迟。

  1. 堆大小-分配给JVM的内存总量。更大的堆意味着GC将花费更多的时间。此外,较大的堆内存意味着与较小的堆内存相比,JVM触发GC不会那么频繁。JVM对此的选项是-Xms=<n> 和-Xmx=<n> 在哪里-Xms表示最小值和-Xmx是最大值。
  2. CPU内核-GC算法因CPU内核数量而异。有些是为单核CPU设计的,有些是为多核CPU设计的。
  3. 应用数据集-这是指应用程序使用的对象的数量。创建更多的新对象会导致年轻一代空间被填满,需要更多的GC时间来释放内存。
  4. 吞吐量-它是完成应用程序任务所需的总时间(不包括GC)的百分比。它与分配给JVM的内存成反比。
  5. 暂停时间-在内存回收期间,GC算法停止应用程序所用的时间。它根据不同的GC算法而变化。对此的JVM选项是-XX:MaxGCPauseMillis=<N>
  6. 潜伏期-这是应用程序的响应时间,直接取决于GC暂停时间。

根据上述参数,你必须选择最适合您的应用程序的GC算法。举个例子,

  • 如果应用程序很小,使用较小的数据集,并且在单个处理器上运行,没有暂停时间要求,则使用串行GC。
  • 如果应用程序性能是最高优先级,则使用并行GC。
  • 当应用程序的响应时间很重要时,使用G1GC或CMS,因为它不会在运行GC时挂起应用程序。

感谢阅读,更多的java课程学习路线,笔记,面试等架构资料,点赞加关注,后台私信“资料”即可获得免费资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值