答案部分取决于他们是在讨论经典的哈希表实现(如Java中的HashTable / HashMap)还是更复杂的东西。最终,按照当今的标准,对于单个机器/ VM来说,30 GB的内存仍然非常大。
所以想想下面发生了什么:
- 必须在某个大规模阵列中的任意位置读取写入。
- 如果它超出某种程度,它必须增长;请参阅Java实现中的“加载因子”。
- 在垃圾收集语言/实现中,存储在哈希表中的所有对象都需要由垃圾收集器进行检查
醇>
导致以下问题:
- 目前尚不清楚即使是今天的操作系统也能很好地分配数十GB的内存块
- 为简单起见,假设表的一半实际上是由表本身使用的(而不是键和值对象)。所以内部有一个15 GB的阵列。因此,每当表增长时,您至少需要分配另一个 15 gb
- 即使分配了数十GB的数组,操作系统也会查看部分内存。由于我们假设一个好的哈希函数,如果我们使用数组中的大部分数据,我们将打破页面缓存。会出现很多页面错误。
- 假设我们不使用所有数据。有些键经常使用,有些则不经常使用。为了说明,假设每个键值很小 - 128个字节。为简单起见,假设我们将所有内容存储在哈希表中作为值。所以30G / 128 = ~250M条目。但是说25k常用键。 (25k / 250M = 0.01%)。但是如果具有良好的散列函数,它们将均匀地分散在大规模阵列中。即使页面尺寸较小 - 比如4kb,25K(条目)* 128字节(条目大小)=〜3.5Mb常用数据也需要25K(条目)* 4K(页面大小)=〜100Mb需要的内存要以高达3.5%的效率保持... ...
- 在Java世界中,从业者不建议堆大小超过4 - 8Gb。当然有像Azul这样的东西,但这只是证明了这一点 - 一个典型的垃圾收集器不能很好地扩展到这些尺寸。
醇>
我同意谷歌正在寻找分布式解决方案的其他海报。但我认为,一个简单的哈希表停止扩展到一个点之外。在上面,
- 如果所有条目都相对均匀地访问,则必须分发
- 如果在大多数情况下访问某些地图,使用两张地图(最常用的地图之一)可能会给你带来很多好处。
- 在Java世界中,使用从堆中存储数据的专用地图也可以为您带来性能;例如,请参阅Peter Lawrey's work。
- 即使简单地在哈希表中对基础数组进行条带化(如Java的ConcurrentHashMap,也可以)在必须增加哈希表时为您提供重大改进。
醇>
我认为面试官期待Distributed Hash table的某些内容,因为30GB的哈希表不能存储在一台机器上(至少在当前的64位世界中);根据我的个人经验,相当多的谷歌Q围绕分布式计算,地图缩减等,