Java (JVM) 内存模型 - Java 中的内存管理

了解 JVM 记忆模型Java 记忆管理非常重要,如果你想了解 Java Garbage Collection的运作方式,今天我们将研究 Java 中的记忆管理、JVM 记忆的不同部分以及如何监控和执行垃圾收集调节。

Java (JVM) 记忆模型

Java Memory Model, JVM Memory Model, Memory Management in Java, Java Memory Management As you can see in the above image, JVM memory is divided into separate parts. At broad level, JVM Heap memory is physically divided into two parts - Young Generation and Old Generation.

Java 内存管理 - 年轻一代

年轻一代是创造所有新物体的地方。当年轻一代被填满时,垃圾收集会进行。这个垃圾收集被称为 Minor GC。年轻一代被分为三个部分 - Eden Memory和两个 Survivor Memory空间。

  • 大多数新创建的对象都位于伊甸记忆空间 *当伊甸空间充满了对象时,小型GC被执行,所有幸存者对象被移动到一个幸存者空间 *小型GC还检查幸存者对象并将它们移动到另一个幸存者空间。

Java 内存管理 - 老一代

Old Generation 記憶體包含那些長壽的物體,並在小型 GC 進行了許多回合後存活。

停止世界事件

所有垃圾收集都是停止世界事件,因为所有应用程序线程都被停止,直到操作完成. 由于年轻一代保持短寿命的对象,小GC非常快,并且应用程序不会受到影响。 然而,大GC需要很长的时间,因为它检查所有活物体。 大GC应该被最小化,因为它会使您的应用程序对垃圾收集的持续时间不响应。 所以,如果你有一个响应性应用程序,并且有很多大垃圾收集发生,你会注意到时间错误。

Java 記憶體模型 - 永久性世代

Perm Gen 包含 JVM 所需的应用程序元数据来描述应用程序中使用的类和方法,请注意 Perm Gen 不是 Java Heap 内存的一部分, Perm Gen 是基于应用程序使用的类而在运行时被 JVM 所占据的。

Java 记忆模型 - 方法区域

方法区域是Perm Gen中空间的一部分,用于存储类结构(运行时常数和静态变量)和方法和构造器的代码。

Java 記憶體模型 - 記憶體池

记忆池由JVM内存管理员创建,以创建一个不变对象池,如果实现支持它,String Pool是这种类型的记忆池的一个很好的例子。

Java 记忆模型 - Runtime Constant Pool

运行时常量池是类中常量池的每类运行时表示,它包含类运行时常量和静态方法,运行时常量池是方法区域的一部分。

Java 记忆模型(Java Stack Memory)

Java Stack 内存用于执行一个线程. 它们包含方法特定的值,这些值是短暂的,以及从方法中引用的堆栈中的其他对象的引用。

Java 内存管理 - Java Heap 内存交换机

Java 提供了大量的内存交换机,我们可以用来设置内存大小和它们的比例。

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

大多数情况下,上述选项是足够的,但如果你想检查其他选项,请检查 JVM 选项官方页面

Java 内存管理 - Java Garbage Collection

Java Garbage Collection 是识别和从内存中删除未使用的对象的过程,并将自由空间分配给在未来处理中创建的对象。 Java 编程语言的最佳功能之一是 自动垃圾收集,与其他编程语言如 C 不同,其中记忆分配和分配是手动的过程。 ** Garbage Collector** 是运行在后台的程序,它查看内存中的所有对象,并找出程序中任何一部分没有引用的对象。

  1. 标记:这是垃圾收集器识别使用的对象和不使用的对象的第一步
  2. 正常删除:垃圾收集器删除未使用的对象,并回收可分配给其他对象的自由空间 。

有两个问题,一个简单的标记和删除方法。

第一,它并不高效,因为大多数新创建的对象将不再使用 2 第二,用于多个垃圾收集周期的对象也更有可能在未来周期中使用

上述简单方法的缺点是 Java Garbage Collection 是 Generational 的原因,并且我们在堆积内存中有 Young GenerationOld Generation 空间。

Java 内存管理 - Java Garbage Collection 类型

有五种类型的垃圾收集类型,我们可以在我们的应用程序中使用。我们只需要使用JVM开关来启用应用程序的垃圾收集策略。

  1. 联合国 ** 连续GC(-XX:+ 使用序列GC): 串行GC对年轻和老一代的垃圾收集,即小和主要GC,采用简单的Mark-sweap-compact**方法. 串行GC在客户机中有用,比如我们的简单的独立应用程序和拥有更小的CPU的机器. 这对内存足迹少的小应用程序有好处.
  2. ** GC(-XX:+UssParallelGC)**: 平行GC与串行GC相同,但这是产卵N线用于年轻一代垃圾收集,其中N是系统中CPU核心的数量. 我们可以使用"-XX:ParallelGCThreads=n"控制线程数. JVM选项. 平行垃圾收集器也被称为吞吐收集器,因为它使用多个CPU来加速GC的性能. 并行GC为"旧世代"垃圾收集使用一线程.
  3. Parallel 旧GC(-XX:+UseParallelOldGC): 这与平行GC相同,只是它同时使用多条线程来收集年轻一代和老一代垃圾.
  4. ** 同时期的Mark Sweep (CMS) 收集器(-XX:+ uses ConcMarkSweepGC)**: CMS采集器也被称为同时存在的低暂停采集器. 它为旧世代的垃圾收集。 CMS收集器试图通过与应用线程同时进行大部分垃圾收集工作来将垃圾收集导致的暂停降到最低. 年轻一代上的CMS采集器使用与平行采集器相同的算法. 这个垃圾收集器适合响应性应用 在那里,我们负担不起更长的暂停时间。 我们可以使用"-XX:ParallelCMSThreads=n"限制CMS收藏器中的线程数量. JVM 选项.
  5. G1垃圾收集器(-XX:+UseG1GC): 垃圾一号或G1垃圾收集器取自Java 7,其长期目标是取代CMS收集器. G1收集器是平行、并行和渐进地压缩低暂停垃圾收集器。 垃圾第一收集器不像其他收藏家那样工作,也没有"年轻与老一代"空间的概念. 它将堆积空间分为多个等大小堆积区域. 当一个垃圾收集被引用时,它首先以较少的活数据来收集这个区域,因此"Garbage First". 您可以在 [Garbage- First Collectionor Oracle Documents] (https://docs.oracle.com/javase/7/docs/technotes/guides/vm/G1.html) 上找到更多关于它的详情

Java 記憶體管理 - Java Garbage Collection Monitoring

我们可以使用 Java 命令行以及 UI 工具来监控应用程序的垃圾收集活动. 作为我的例子,我正在使用由 Java SE 下载提供的演示应用程序之一. 如果您想使用相同的应用程序,请访问 Java SE 下载页面并下载 JDK 7 和 JavaFX Demos and Samples。 我正在使用的样本应用程序是 Java2Demo.jar,它存在于 jdk1.7.0_55/demo/jfc/Java2D目录中。

1pankaj@Pankaj:~/Downloads/jdk1.7.0_55/demo/jfc/Java2D$ java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar Java2Demo.jar

以色列

我们可以使用jstat命令行工具来监控JVM内存和垃圾收集活动,它配备了标准的JDK,所以你不需要做任何其他事情来获取它。

1pankaj@Pankaj:~$ ps -eaf | grep Java2Demo.jar
2  501 9582 11579 0 9:48PM ttys000 0:21.66 /usr/bin/java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseG1GC -jar Java2Demo.jar
3  501 14073 14045 0 9:48PM ttys002 0:00.00 grep Java2Demo.jar

所以我的Java应用程序的过程ID是9582.现在我们可以运行 jstat命令,如下所示。

1pankaj@Pankaj:~$ jstat -gc 9582 1000
2 S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
31024.0 1024.0 0.0 0.0 8192.0 7933.3 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
41024.0 1024.0 0.0 0.0 8192.0 8026.5 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
51024.0 1024.0 0.0 0.0 8192.0 8030.0 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
61024.0 1024.0 0.0 0.0 8192.0 8122.2 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
71024.0 1024.0 0.0 0.0 8192.0 8171.2 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
81024.0 1024.0 48.7 0.0 8192.0 106.7 42108.0 23401.3 20480.0 19990.9 158 0.275 40 1.381 1.656
91024.0 1024.0 48.7 0.0 8192.0 145.8 42108.0 23401.3 20480.0 19990.9 158 0.275 40 1.381 1.656

jstat的最后一个论点是每个输出之间的时间间隔,因此它将每1秒打印记忆和垃圾收集数据。

  • ** S0C和S1C**: 本列显示 KB. () 中的幸存者和幸存者1 区域的当前大小 。 ) * ** S0U和S1U**: 本列显示KB中Survivor0和Survivor1地区的当前用法. 注意幸存区域之一始终为空. ( ( )* ** 欧共体和欧盟**: 这些列显示了KB中伊甸园空间的当前大小和用途. 请注意,欧盟的规模正在扩大,一旦跨越欧共体,就称为小型GC并缩小欧盟的规模。 (_ ( )* ** OC和OU**: 这些列在 KB. () 中显示旧生成的当前大小和当前用途 。 ) * PC和PU: 这些列在 KB. () 中显示 Perm Gen 的当前大小和当前用途 。 ( )* ** YGC和YGCT**:YGC一栏显示年轻一代时发生的GC事件数量. YGCT一栏显示为"年轻一代"进行GC操作的累计时间. 注意两者在欧盟值因小GC. 而下降的同行中均增加* ** FGC和FGCT**:FGC一栏显示发生完全GC事件的次数. FGCT一栏显示完全GC运行的累积时间. 注意与年轻一代GC计时相比,全GC时间太高。 (_) ( )* GCT:本栏显示GC运行所积累的总时间. 通知其为YGCT和FGCT列值之和. ( (英语)

jstat的优点在于它也可以在我们没有GUI的地方在远程服务器上执行,请注意S0C,S1C和EC的总和是通过-Xmn10mJVM选项指定的10m。

使用Visual GC的Java VisualVM

If you want to see memory and GC operations in GUI, then you can use jvisualvm tool. Java VisualVM is also part of JDK, so you don't need to download it separately. Just run jvisualvm command in the terminal to launch the Java VisualVM application. Once launched, you need to install Visual GC plugin from Tools -< Plugins option, as shown in below image. VisualVM-Visual-GC-Plugin After installing Visual GC, just open the application from the left side column and head over to Visual GC section. You will get an image of JVM memory and garbage collection details as shown in below image. Serial-GC-VisualGC

Java Garbage 集合调制

Java Garbage Collection Tuning应该是您应该使用的最后一种选择,以增加应用程序的输出量,只有当您看到性能下降时,因为更长的 GC 时间会导致应用程序时间消失. 如果您看到java.lang.OutOfMemoryError: PermGen 空间的错误在日志中,然后尝试监控并增加 Perm Gen 内存空间使用 -XX:PermGen 和 -XX:MaxPermGen JVM 选项。您也可以尝试使用 `-XX:+CMSClassUnloadingEnabled’并检查它如何与 CMS Garbage 收集器一起运作。如果您看到大量的完整 GC 操作,那么您应该尝试增加旧代记忆空间。 总体上垃圾收集调节需要大量的精力和时间,而且没有任何

Published At
Categories with 技术
Tagged with
comments powered by Disqus