谷歌面试问题

时间:2011-09-06 06:34:43

标签: java c++ hashtable

这是Google采访问题之一。

  

如果哈希表增长超过30 GB,可能会出现什么问题   (忽略糟糕的哈希函数等问题)

我不知道。什么可以得到满意的答案?

由于

3 个答案:

答案 0 :(得分:22)

答案部分取决于他们是在讨论经典的哈希表实现(如Java中的HashTable / HashMap)还是更复杂的东西。最终,按照当今的标准,对于单个机器/ VM来说,30 GB的内存仍然非常大。

所以想想下面发生了什么:

  1. 必须在某个大规模阵列中的任意位置读取写入。
  2. 如果它超出某种程度,它必须增长;请参阅Java实现中的“加载因子”。
  3. 在垃圾收集语言/实现中,存储在哈希表中的所有对象都需要由垃圾收集器进行检查
  4. 导致以下问题:

    1. 目前尚不清楚即使是今天的操作系统也能很好地分配数十GB的内存块
    2. 为简单起见,假设表的一半实际上是由表本身使用的(而不是键和值对象)。所以内部有一个15 GB的阵列。因此,每当表增长时,您至少需要分配另一个 15 gb
    3. 即使分配了数十GB的数组,操作系统也会查看部分内存。由于我们假设一个好的哈希函数,如果我们使用数组中的大部分数据,我们将打破页面缓存。会出现很多页面错误。
    4. 假设我们使用所有数据。有些键经常使用,有些则不经常使用。为了说明,假设每个键值很小 - 128个字节。为简单起见,假设我们将所有内容存储在哈希表中作为值。所以30G / 128 = ~250M条目。但是说25k常用键。 (25k / 250M = 0.01%)。但是如果具有良好的散列函数,它们将均匀地分散在大规模阵列中。即使页面尺寸较小 - 比如4kb,25K(条目)* 128字节(条目大小)=〜3.5Mb常用数据也需要25K(条目)* 4K(页面大小)=〜100Mb需要的内存要以高达3.5%的效率保持... ...
    5. 在Java世界中,从业者不建议堆大小超过4 - 8Gb。当然有像Azul这样的东西,但这只是证明了这一点 - 一个典型的垃圾收集器不能很好地扩展到这些尺寸。
    6. 我同意谷歌正在寻找分布式解决方案的其他海报。但我认为,一个简单的哈希表停止扩展到一个点之外。在上面,

      1. 如果所有条目都相对均匀地访问,则必须分发
      2. 如果在大多数情况下访问某些地图,使用两张地图(最常用的地图之一)可能会给你带来很多好处。
      3. 在Java世界中,使用从堆中存储数据的专用地图也可以为您带来性能;例如,请参阅Peter Lawrey's work
      4. 即使简单地在哈希表中对基础数组进行条带化(如Java的ConcurrentHashMap,也可以)在必须增加哈希表时为您提供重大改进。

答案 1 :(得分:7)

我认为面试官期待Distributed Hash table的某些内容,因为30GB的哈希表不能存储在一台机器上(至少在当前的64位世界中);根据我的个人经验,相当多的谷歌Q围绕分布式计算,地图缩减等,

答案 2 :(得分:5)

一些问题:

  1. Hash Collision可能是可能遇到的主要问题之一。
  2. 当磁盘中的数据存储为哈希表时,频繁进行磁盘读取也是低效的。