“堆上”和“堆外”的区别

Ehcache 谈论堆上和离堆内存。有什么区别? 用什么 JVM 参数来配置它们?

123765 次浏览

JVM 对离堆内存一无所知,Ehcache 实现了磁盘缓存和内存缓存。

不是100% ; 然而,这听起来像是堆是一个对象或分配的空间集(在 RAM 上) ,内置到代码的功能或 Java 本身或更可能的功能来自 ehcache 本身,和离堆 RAM 也有自己的系统; 然而,这听起来像是一个数量级慢,因为它不是有组织的,这意味着它可能不使用堆(意味着一个长的集内存空间) ,而是使用不同的地址空间可能使它稍微低效。

当然,下一层是硬盘空间本身。

我不用 Ehcache 所以你可能不会信任我但这是我从他们的文档中得到的信息。

堆上存储引用将出现在 Java 堆中的对象(也受 GC 控制)。另一方面,离堆存储引用 EHCache 管理的(序列化的)对象,但是存储在堆之外(也不受 GC 控制)。由于离堆存储继续在内存中进行管理,因此它比堆上存储稍慢,但仍然比磁盘存储快。

在问题中发布的链接中,关于离线堆存储的管理和使用的内部详细信息并不十分明显,因此查看用于管理离线磁盘存储的 兵马俑大记忆体的详细信息将是明智的。BigMemory (离堆存储)用于避免大小为几兆字节或几千兆字节的堆上的 GC 开销。BigMemory 通过 直接字节缓冲区使用 JVM 进程的内存地址空间,与其他本机 Java 对象不同,这些内存地址空间不受 GC 的约束。

堆是内存中动态分配的对象所在的位置。如果你使用 new,那么它在堆上。这与堆栈空间相反,堆栈空间是函数堆栈所在的位置。如果您有一个局部变量,那么该引用位于堆栈上。 Java 的堆受到垃圾收集的影响,对象可以直接使用。

EHCache 的离堆存储将您的常规对象从堆中取出,序列化它,并将它作为字节存储在 EHCache 管理的一块内存中。就像是存储在磁盘上,但是还是在内存里。这些对象在这种状态下不能直接使用,必须首先对它们进行反序列化。也不受垃圾收集的影响。

http://code.google.com/p/fast-serialization/wiki/QuickStartHeapOff

什么是堆卸?

通常所有分配的非临时对象都由 Java 的垃圾收集器管理。虽然虚拟机在垃圾收集方面做得不错,但在某个时刻虚拟机必须执行所谓的“完全 GC”。完整的 GC 需要扫描完整分配的堆,这意味着 GC 暂停/减速与应用程序堆大小成正比。因此,不要相信任何人告诉你“记忆是廉价的”。在 Java 中内存消耗会影响性能。此外,如果堆大小 > 1Gb,可能会出现明显的暂停。如果您正在进行任何接近实时的操作,那么在集群或网格中,Java 进程可能会失去响应并从集群中删除,这种情况可能非常糟糕。

然而,今天的服务器应用程序(通常构建在臃肿的框架之上; ——)很容易需要远远超过4Gb 的堆。

解决这些内存需求的一个方法是将对象的一部分“卸载”到非 java 堆(直接从操作系统分配)。幸运的是,java.nio 提供了直接分配/读取和写入“非托管”内存块(甚至是内存映射文件)的类。

因此,可以分配大量的“非托管”内存,并使用它来保存对象。为了将任意对象保存到非托管内存中,最可行的解决方案是使用序列化。这意味着应用程序将对象序列化到离堆内存中,稍后可以使用反序列化读取对象。

由 java VM 管理的堆大小可以保持很小,因此 GC 暂停是毫秒级的,每个人都很高兴,工作完成了。

很明显,这种离堆缓冲区的性能主要取决于序列化实现的性能。好消息: 出于某种原因,FST 序列化非常快: ——)。

使用场景示例:

  • 服务器应用程序中的会话缓存。使用内存映射文件存储千兆字节(非活动)用户会话。一旦用户登录到应用程序中,您就可以快速访问与用户相关的数据,而不必处理数据库。
  • 缓存计算结果(查询、 html 页面、 . .)(仅适用于计算速度慢于反序列化结果对象 ofc 的情况)。
  • 使用内存映射文件的非常简单和快速的持久性

编辑: 对于某些场景,可以选择更复杂的垃圾收集算法,如 ConcurrentMarkAndSweep 或 G1,以支持更大的堆(但这也有其超过16GB 堆的限制)。还有一个商业 JVM,它改进了“暂停”GC (Azul)。

简而言之

Java On/Off Heap storage in short

片尾字幕


详细的照片

Java On/Off Heap storage in details

片尾字幕