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

2022-08-31 06:47:05

Ehcache 谈到了堆上和堆外内存。有什么区别?使用什么 JVM 参数来配置它们?


答案 1

堆上存储是指将存在于 Java 堆中的对象(并且还受 GC 的约束)。另一方面,堆外存储是指由 EHCache 管理但存储在堆外部(也不受 GC 约束)的(序列化)对象。由于堆外存储继续在内存中进行管理,因此它比堆上存储稍慢,但仍然比磁盘存储快。

在问题中发布的链接中,管理和使用堆外存储所涉及的内部详细信息并不是很明显,因此最好查看用于管理磁盘外存储的Terracotta BigMemory的详细信息。BigMemory(堆外存储)用于避免在几兆字节或千兆字节大的堆上产生 GC 的开销。BigMemory使用JVM进程的内存地址空间,通过直接的ByteBuffers,与其他本机Java对象不同,这些字节缓冲器不受GC的约束。


答案 2

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

什么是堆卸载?

通常,您分配的所有非临时对象都由java的垃圾回收器管理。尽管 VM 在执行垃圾回收方面做得很好,但在某一时刻,VM 必须执行所谓的“完整 GC”。完整的 GC 涉及扫描完全分配的堆,这意味着 GC 暂停/减速与应用程序堆大小成正比。所以不要相信任何人告诉你“内存很便宜”。在java内存消耗中会损害性能。此外,使用堆大小> 1 Gb 时,可能会出现明显的暂停。如果您有任何近乎实时的东西正在运行,这可能会很讨厌,在集群或网格中,Java进程可能会无响应并从集群中删除。

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

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

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

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

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

示例使用方案:

  • 服务器应用程序中的会话缓存。使用内存映射文件存储数 GB(非活动)用户会话。用户登录到应用程序后,您可以快速访问与用户相关的数据,而无需处理数据库。
  • 缓存计算结果(查询、html 页面、..)(仅当计算比反序列化结果对象 ofc 慢时才适用)。
  • 使用内存映射文件进行非常简单和快速的持久化

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


推荐