我前几天看到演讲者使用了McIlroy的论文 A Killer Adversary for Quicksort 中概述的技术来为Arrays.sort
生成一个输入,用于触发将触发的原始类型O(n 2 )行为。该序列导致pivot选择总是只减少一个常量,这导致Java Arrays.sort
函数导致堆栈溢出。
根据the source files from the JDK,Arrays.sort1
快速排序实现功能无法防止堆栈溢出。通过使排序例程不会触发两个递归调用,总是可以使快速排序永远不会堆栈溢出,而是使用while循环来重用当前堆栈帧以用于更大的子数组并且仅递归一次(在较小的子数组上)。这导致最小的性能下降,并且使得不可能导致任何合理大小的输入的堆栈溢出,因为堆栈深度从不超过大小为n的输入上的O(log n)堆栈帧。作者还可以使用introsort算法,当快速排序递归深度超过某个限制时,它会修改快速排序以切换到最坏情况的O(n log n)排序算法,以防止这种情况。
有Arrays.sort
的作者没有选择这样做的原因吗?内置的排序算法可能会导致堆栈溢出,这似乎是一个严重的问题,因为它可以通过触发重复的堆栈溢出来对这样的系统发起DoS攻击。
答案 0 :(得分:5)
为什么呢?因为解决这个问题会有点过头了。
所使用的算法在所有异常情况下都会保持稳定,如果这些情况通常可能发生,那么情况就会受到外部防范。这就是为什么他们有API文档来定义幕后使用的算法。所以你可以抵御它。
破坏所呈现算法的特定顺序的可能性非常小。
我希望如果你仔细观察会有数据集导致几乎所有的标准JVM结构中断。 防御它们的成本是多少,并且由于防御措施,成本值得付出努力并且算法不可避免地会退化。