244

我目前正在使用 jconsole 监控 Java 应用程序。内存选项卡可让您选择:

Heap Memory Usage
Non-Heap Memory Usage
Memory Pool “Eden Space”
Memory Pool “Survivor Space”
Memory Pool “Tenured Gen”
Memory Pool “Code Cache”
Memory Pool “Perm Gen”

它们之间有什么区别?

4

5 回答 5

353

堆内存

堆内存是 Java VM 为所有类实例和数组分配内存的运行时数据区域。堆的大小可以是固定的或可变的。垃圾收集器是一种自动内存管理系统,用于回收对象的堆内存。

  • Eden Space:最初为大多数对象分配内存的池。

  • Survivor Space:包含在 Eden 空间的垃圾收集中幸存下来的对象的池。

  • Tenured GenerationOld Gen:包含在幸存者空间中已存在一段时间的对象的池。

非堆内存

非堆内存包括在所有线程之间共享的方法区域以及 Java VM 内部处理或优化所需的内存。它存储每个类的结构,例如运行时常量池、字段和方法数据,以及方法和构造函数的代码。方法区域在逻辑上是堆的一部分,但根据实现,Java VM 可能不会垃圾收集或压缩它。与堆内存一样,方法区的大小可以是固定的或可变的。方法区的内存不需要是连续的。

  • Permanent Generation:包含虚拟机本身的所有反射数据的池,例如类和方法对象。对于使用类数据共享的 Java VM,这一代分为只读区和读写区。

  • 代码缓存:HotSpot Java VM 还包括一个代码缓存,其中包含用于编译和存储本机代码的内存。

这是一些关于如何使用 Jconsole 的文档

于 2009-08-11T19:42:50.420 回答
84

关键字在newJava 堆上分配内存。堆是主内存池,可供整个应用程序访问。如果没有足够的内存可供该对象分配,JVM 会尝试通过垃圾回收从堆中回收一些内存。如果它仍然无法获得足够的内存,OutOfMemoryError则抛出 an 并且 JVM 退出。

堆被分成几个不同的部分,称为世代。随着对象在更多的垃圾收集中存活,它们被提升到不同的代。老一代不经常收集垃圾。因为这些对象已经被证明寿命更长,所以它们不太可能被垃圾收集。

当对象第一次被构造时,它们被分配在 Eden Space 中。如果他们在垃圾收集中幸存下来,他们就会被提升到幸存者空间,如果他们在那里生活的时间足够长,他们就会被分配到 Tenured Generation。这一代的垃圾收集频率要低得多。

还有第四代,称为永久一代,或 PermGen。驻留在此处的对象不适合进行垃圾回收,并且通常包含 JVM 运行所必需的不可变状态,例如类定义和字符串常量池。请注意,PermGen 空间计划从 Java 8 中删除,并将替换为名为 Metaspace 的新空间,该空间将保存在本机内存中。参考:http://www.programcreek.com/2013/04/jvm-run-time-data-areas/

多个线程的Java内存图 Java内存分布图

于 2016-05-08T17:19:31.233 回答
35

With Java8, non heap region no more contains PermGen but Metaspace, which is a major change in Java8, supposed to get rid of out of memory errors with java as metaspace size can be increased depending on the space required by jvm for class data.

于 2014-06-18T05:30:03.620 回答
24

Java 堆内存是操作系统分配给 JVM 的内存的一部分。

对象驻留在称为堆的区域中。堆是在 JVM 启动时创建的,并且在应用程序运行时可能会增加或减少大小。当堆满时,垃圾会被收集。

在此处输入图像描述

您可以在下面的 SE 问题中找到有关Eden Space、Survivor Space、Tenured Space 和 Permanent Generation的更多详细信息:

Young , Tenured 和 Perm 一代

自 Java 8 发布以来,PermGen 已被 Metaspace 取代。

关于您的查询:

  1. Eden Space、Survivor Space、Tenured Space 是堆内存的一部分
  2. 元空间和代码缓存是非堆内存的一部分。

代码缓存: Java 虚拟机 (JVM) 生成本机代码并将其存储在称为代码缓存的内存区域中。JVM 出于多种原因生成本机代码,包括动态生成的解释器循环、Java 本机接口 (JNI) 存根以及由即时 (JIT) 编译器编译为本机代码的 Java 方法。JIT 是迄今为止最大的代码缓存用户。

于 2016-06-06T12:45:36.250 回答
1

堆分为年轻代和年老代,如下所示:

年轻代:是一个对象短暂存在的地方,分为两个空间:

  • 伊甸园空间:当使用新关键字创建对象时,在此空间上分配内存。
  • 幸存者空间(S0 和 S1):这是一个池,其中包含在从 Eden 空间进行少量 Java 垃圾回收后幸存的对象。

老一代:这个池基本上包含永久和虚拟(保留)空间,并将保存那些在年轻一代的垃圾收集后幸存下来的对象。

  • Tenured Space:此内存池包含在多次垃圾回收后幸存的对象,是指从 Survivor 空间进行垃圾回收后幸存的对象。

在此处输入图像描述

解释

假设我们的应用程序刚刚启动。

所以此时所有这三个空间都是空的(Eden,S0,S1)。

每当创建一个新对象时,它就会被放置在 Eden 空间中。

当 Eden 空间已满时,垃圾收集过程(次要 GC)将在 Eden 空间上进行,并且任何幸存的对象都将移至 S0。

然后,我们的应用程序继续运行,在垃圾收集过程下一次运行时在 Eden 空间中创建新对象,它会查看 Eden 空间和 S0 中的所有内容,并且任何幸存的对象都被移动到 S1 中。

PS:根据对象应该在Survivor空间存活多少时间的配置,对象也可能来回移动到S0和S1,然后达到阈值对象会被移动到老年代堆空间。

于 2020-12-13T05:59:50.893 回答