“堆上”和“堆外”的区别
Ehcache 谈论堆内和堆外存储器。 有什么不同? 用什么JVM参数来configuration它们?
堆上存储是指将出现在Java堆中的对象(也受GC支配)。 另一方面,堆外存储指的是由EHCachepipe理的(序列化的)对象,但存储在堆外(也不受GC支配)。 由于堆内存库继续在内存中进行pipe理,因此它比堆内存储稍慢,但仍比磁盘存储更快。
涉及pipe理和使用堆外存储的内部细节在问题中发布的链接中并不是非常明显,因此,检查用于pipe理离线磁盘的Terracotta BigMemory的详细信息将是明智之举商店。 BigMemory(堆外存储)用于避免GC在几兆或几千兆字节大小的堆栈上的开销。 BigMemory使用JVM进程的内存地址空间,通过不受GC影响的直接ByteBuffers ,与其他本地Java对象不同。
来自http://code.google.com/p/fast-serialization/wiki/QuickStartHeapOff
什么是堆卸载?
通常,您分配的所有非临时对象都由java的垃圾收集器pipe理。 尽pipe虚拟机在做垃圾收集方面做得不错,但在某个时候,虚拟机必须做一个所谓的“完整的GC”。 完整的GC涉及扫描完整分配的堆,这意味着GC暂停/减速与应用程序堆大小成正比。 所以不要相信有人告诉你“记忆力便宜”。 在Java内存消耗损害性能。 此外,您可能会使用堆大小> 1 GB的显着暂停。 这可能是讨厌的,如果你有任何接近实时的东西进行,在一个集群或网格中,java进程可能无响应,并从集群中删除。
然而,今天的服务器应用程序(通常build立在笨拙的框架之上;-))很容易要求超过4Gb的堆。
解决这些内存需求的一个办法是将部分对象卸载到非Java堆(从操作系统直接分配)。 幸运的是,java.nio提供了直接分配/读取和写入“非托pipe”内存块(甚至是内存映射文件)的类。
所以可以分配大量的“非托pipe”内存,并使用它来保存对象。 为了将任意对象保存到非托pipe内存中,最可行的解决scheme是使用序列化。 这意味着应用程序将对象序列化到offheap内存中,以后可以使用反序列化来读取对象。
由Java虚拟机pipe理的堆大小可以保持很小,所以GC暂停在毫秒,大家都很高兴,工作完成。
很明显,这种堆外缓冲区的性能主要取决于序列化实现的性能。 好消息:出于某种原因,FST序列化相当快:-)。
示例使用情况:
- 会话caching在服务器应用程序中。 使用内存映射文件来存储千兆字节(不活动)的用户会话。 一旦用户login到您的应用程序,您可以快速访问用户相关的数据,而无需处理数据库。
- 计算结果(查询,html页面,…)的caching(仅适用于计算比反序列化结果对象ofc更慢的情况)。
- 使用内存映射文件非常简单和快速的持久性
编辑:对于一些场景,可能会select更复杂的垃圾收集algorithm,如ConcurrentMarkAndSweep或G1来支持更大的堆(但也有其限制超过16GB堆)。 还有一个商业的JVM,改进了“pauseless”GC(Azul)。
堆是你的dynamic分配对象所在的内存中的地方。 如果你使用new
那么它在堆上。 这与堆栈空间相反,堆栈空间是函数堆栈所在的地方。 如果你有一个局部variables,那么这个引用是在栈上。 Java的堆是垃圾收集和对象可直接使用。
EHCache的堆外存储将常规对象从堆中取出,序列化,并将其作为字节存储在EHCachepipe理的内存块中。 就像存储到磁盘,但它仍然在RAM中。 这些对象在这个状态下不能直接使用,所以它们必须先被反序列化。 也不受垃圾收集。
简而言之,
图片信用
详细的图片
图片信用
不是100% 然而,这听起来像堆是一个对象或一组分配的空间(在RAM上),它是内置于代码function的Java本身,或者更有可能来自ehcache本身的function,并且堆外Ram有自己的系统好; 然而,这听起来像是慢了一个数量级,因为它不是有组织的,这意味着它可能不会使用一堆(意味着一个长的RAM空间),而是使用不同的地址空间,可能会使其效率略低。
那么下一层当然就是硬盘空间本身。
我不使用ehcache,所以你可能不想相信我,但是我从他们的文档中得到了什么。
JVM不知道关于堆内存的任何内容。 Ehcache实现了一个磁盘caching以及一个内存中caching。