【问题标题】:Julia Vector: Excessive Memory UsageJulia Vector:内存使用过多
【发布时间】:2021-12-21 10:20:44
【问题描述】:

我想使用中间相遇攻击来暴力破解 64 位 RSA 加密文本(这是针对大学的,没有恶意)。

为此,我基本上创建了一个具有 2^34 个 BigInt 值的 Julia 向量,并在其上广播 powermod() 方法以将值替换为结果。

v = powermod.(collect(1:2^34), e, n)

n 在这种情况下是 1024 位长,理论上应该导致 2^34 * 1024 位大小加上开销的向量。但是,如果我尝试创建一个较小的向量(例如 2^20),它已经分配了 4GB 的内存。

const e = 65537
const n = 146524179203462820907751077702895222709717245613911342138636679265720963659264803540209990978140003809112749926543448691815554807130673470903067642157383639213843567573216381956709789503739105865173848988830139432801516289108538638198344024523424071181688467967187076534718264943427915623567859427045475866239

@time begin
    v = (powermod.(collect(1:2^24), e, n))
end

@time 的输出

125.598926 seconds (117.44 M allocations: 4.000 GiB, 5.35% gc time)

不确定我在这里做错了什么以及是否做错了什么。任何帮助将不胜感激..

【问题讨论】:

  • 你为什么collecting这个范围? Julia 完全有能力迭代 range 对象而不将其分配到向量中。
  • 请提供一个 MWE,包括打印发布结果的 @time 行,您的代码甚至不会运行,因为 en 未定义。您在哪里创建 BigInt 数组并不明显。
  • @NilsGudat 感谢您指出这一点。但是,这只会将分配的内存减少到3.875 GiB
  • @BatWannaBe 我编辑了帖子以提供 MWE。这将需要一些时间来执行,但您可以将 24 减少到更小的数字以进行测试。

标签: arrays memory vector julia


【解决方案1】:

这是可以像v 一样被索引和迭代的东西,但它在索引时进行计算。由于它不分配结果数组,因此您不能设置像v[i] = x 这样的索引,这可能是您需要的。

struct Laz{F}
  f::F
  size::Int64
end

# v[i]
function Base.getindex(v::Laz, i)
  if i < 1 || i > v.size
    throw(BoundsError(v, i))
  else
    v.f(i)
  end
end

# for el in v
function Base.iterate(v::Laz, state=1)
  if state > v.size
    nothing
  else
    (v[state], state+1)
  end
end

# enables collect(v_lazy) to unlazy the array
Base.length(v::Laz) = v.size

v_lazy = Laz( (x) -> powermod(x, e, n) , 2^24)

v_lazy 进入堆栈,Base.summarysize(v_lazy) 报告 8 个字节,所以这是尽可能节省内存的。不过,每次您索引和计算 BigInts 时,您都会进行分配。如果您迭代 v_lazy,您最终会为 v 分配一定比例的内存,只是增量分配和释放,而不是在一个庞大的数组中一次全部释放。

【讨论】:

    【解决方案2】:

    我认为您没有做错任何事情,当您使用 BigInt 时,您使用的是 powermod 的不同方法,这不是免费分配的:

    julia> @btime powermod(1000, e, 100);
      370.048 ns (0 allocations: 0 bytes)
    
    julia> @btime powermod(1000, e, n);
      6.320 μs (9 allocations: 280 bytes)
    
    julia> @which powermod(1000, e, 100)
    powermod(x::Integer, p::Integer, m::T) where T<:Integer in Base at intfuncs.jl:358
    
    julia> @which powermod(1000, e, n)
    powermod(x::Integer, p::Integer, m::BigInt) in Base.GMP at gmp.jl:615
    

    因此,您不仅要分配结果向量,还要在中间计算期间。关于 Julia Discourse 有很多关于 BigInts 的性能限制的讨论,但我从未真正与他们合作过,所以很遗憾在这里没有任何关于如何加快速度的建议!

    【讨论】:

    • 我明白了.. 非常感谢!我想知道为什么在 powermod 函数返回结果后不只是释放内存。
    • @time 报告的内存是执行期间分配的内存总量,其中包括释放的内存。检查Base.summarysize(v) 以获取最终分配的实际内存。
    猜你喜欢
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多