是否可以从gc透视图标记不可收集的java对象以节省gc-sweep时间?

时间:2012-07-04 15:48:54

标签: java garbage-collection

是否可以从gc透视图标记不可收集的java对象以节省gc-sweep时间?

那里有http://wwwasd.web.cern.ch/wwwasd/lhc++/Objectivity/V5.2/Java/guide/jgdStorage.fm.html和特别是非垃圾收集容器的东西(非垃圾收集?)。

问题是我有很多普通的临时对象,但是我有更大的(几个Gigs)对象存储用于缓存目的。 Java GC无缘无故地遍历所有那些试图找到要收集的内容的Cache千兆字节,因为它们包含有自己超时的缓存数据。

通过这种方式,我可以将自定义方式的数据划分为无限期和正常生活的对象,并且希望GC速度非常快,因为普通对象的生存时间不长,而且数量较少。

这个问题有一些解决方法,例如Apache DirectMemory和商业Terracotta BigMemory(http://terracotta.org/products/bigmemory),但是java-native解决方案会更好(我的意思是免费的)可能更可靠?)。此外,我想避免序列化开销,这意味着它应该在相同的jvm内发生。据我所知,DirectMemory和BigMemory主要运行 off heap ,这意味着必须将对象序列化/反序列化到jvm之外的内存中。简单地在jvm中标记非gc区域似乎是更好的解决方案。使用文件进行缓存也不是一种选择,它具有相同的无法承受的序列化/反序列化开销 - 用例是一个HA服务器,其中包含大量以随机(人工)顺序使用的数据并且需要低延迟。

5 个答案:

答案 0 :(得分:2)

JVM管理的任何内存也由JVM进行垃圾收集。任何直接可用于Java方法而没有反序列化的“实时”对象必须存在于JVM内存中。因此,根据我的理解,你不能拥有对垃圾收集免疫的活体对象。

另一方面,您描述的用法应该使垃圾收集的代际方法非常有效。如果你的大物体停留一段时间,他们将不经常检查填海。所以我怀疑避免这些检查会有很多好处。

答案 1 :(得分:1)

  

是否可以从gc透视图标记不可收集的java对象以节省gc-sweep时间?

不,这是不可能的。

您可以通过保持对象可以访问来阻止对象进行垃圾回收,但GC仍然需要跟踪它们以检查每个对象的可访问性; GC(至少)。

  

只是我的假设,当jvm挨饿时,它也会开始扫描所有不必要的物体。

是。那是正确的。但是,除非你有很多想要以这种方式对待的对象,否则开销可能是微不足道的。 (无论如何,更好的想法是给JVM更多的内存......如果可能的话。)

答案 2 :(得分:0)

很简单,为了能够做到这一点,垃圾收集算法需要知道这样的标志,并在进行工作时将其考虑在内。

我不知道任何标准的GC算法都有这样的标志,所以要做到这一点,你需要编写自己的GC算法(在决定以某种可行的方式将这些信息传递给它之后)。 / p>

事实上,事实上,你已经开始了这条轨道 - 你决定如何进行垃圾收集,而不是乐于将它留给JVM的GC算法。您描述的情况是否适合您;现有垃圾收集不足的东西,但你的计划会有效吗?垃圾收集器调整得非常好,所以如果“低效”的默认策略实际上比你天真的最优策略快,我也不会感到惊讶。

(在最好的情况下进行手动内存管理很棘手且容易出错;在使用库存垃圾收集器处理其余内容时自己管理某些内存似乎更糟糕。我希望你能做到遇到很多边缘情况,GC认为它“知道”整个堆发生了什么,这将不再是真的。如果可以的话,转向清楚......)

答案 3 :(得分:0)

建议的方法是使用商业RTSJ实现来避免GC,或者使用非堆内存。人们也可以查看缓存的软引用(它们确实被收集)。

不建议这样做: 如果由于某种原因您不相信这些选项是足够的,您可以查看直接内存访问,这是UNSAFE(sun.misc.Unsafe的一部分)。您可以使用'theUnsafe'字段来获取'不安全'实例。 Unsafe允许通过'allocateMemory'和'freeMemory'分配/释放内存。这不受GC控制,也不受JVM堆大小的限制。一旦你沿着这条路走下去,对GC /应用程序的影响是不可保证的 - 这就是为什么使用字节缓冲区可能就是这样的原因(如果你没有使用类似RTSJ的实现)。

希望这会有所帮助。

答案 4 :(得分:0)

Living Java对象将始终成为GC生命周期的一部分。或者换句话说,将对象标记为非gc与使用根引用(例如静态最终映射)引用对象的开销顺序相同。

但是进一步思考,放入缓存的数据最有可能是暂时的,最终会被逐出。此时,您将再次开始喜欢JVM和GC。 如果您有100个GB的永久数据,您可能需要重新考虑应用程序的体系结构,并尝试分片和分发数据(水平可伸缩性)。

最后但并非最不重要的是,围绕序列化已经做了很多工作,序列化的开销(我不是在谈论ObjectInputStream和ObjectOutputStream的不良声誉)并不是那么大。 更重要的是,如果您的数据主要由原始类型(包括字节数组)组成,则有效的方法来自 off heap 缓冲区中的readInt()或readBytes()(用于实例netty.io's ChannelBuffer )。这可能是一种方法。