内存分配器


11

您正在设计一种新的深奥编程语言,并且决定添加的一个功能是动态内存分配器。您的语言为用户的程序空间指定了特殊的专用虚拟地址空间。这与内存分配器用于任何内部状态的地址空间是分开的。

为了帮助减少分发实现的成本,代码的大小必须尽可能小。

接口

您必须提供三个功能:初始化,分配和取消分配。

初始化

此函数采用单个正整数参数N。这意味着用户程序N的地址空间中有N-1字节,可以从中分配字节。该地址0保留为“ null”。

确保在任何分配/取消分配调用之前,该函数将被精确地调用一次。

请注意,此功能不需要为用户程序的虚拟地址空间分配任何物理内存。您基本上是在创建空心内存分配器的“外观”。

分配

分配功能必须请求分配的内存字节数。输入保证为正。

您的函数必须将一个整数地址返回到分配的块的开头,或者0表示没有所请求大小的连续块可用。如果在地址空间中的任何地方都有可用大小的连续块,则必须分配!

您必须确保没有两个分配的块重叠。

解除分配

解除分配功能必须采用已分配块的开始地址,并且可以选择采用给定块的大小。

已释放的内存可再次用于分配。假定输入地址是有效地址。

示例Python实现

请注意,您可以选择任何方法来跟踪内部状态。在此示例中,类实例对其进行跟踪。

class myallocator:
    def __init__(self, N):
        # address 0 is special, it's always reserved for null
        # address N is technically outside the address space, so use that as a
        # marker
        self.addrs = [0, N]
        self.sizes = [1, 0]

    def allocate(self, size):
        for i,a1,s1,a2 in zip(range(len(self.addrs)),
                                 self.addrs[:-1], self.sizes[:-1],
                                 self.addrs[1:]):
            if(a2 - (a1+s1) >= size):
                # enough available space, take it
                self.addrs.insert(i+1, a1+s1)
                self.sizes.insert(i+1, size)
                return a1+s1
        # no contiguous spaces large enough to take our block
        return 0

    def deallocate(self, addr, size=0):
        # your implementation has the option of taking in a size parameter
        # in this implementation it's not used
        i = self.addrs.index(addr)
        del self.addrs[i]
        del self.sizes[i]

计分

这是代码高尔夫;以字节为单位的最短代码获胜。您不必担心分配器所需的任何内部状态都会耗尽内存。

标准环孔适用。

排行榜


3
我怀疑Python列表每个元素仅占用一个字节。“分配的内存”是否必须以字节为单位,或者仅仅是“您的语言的通用数组/列表类型”?
门把手

4
不需要实际分配(除了您想要进行内部状态跟踪的任何内容外,它都位于其自己的虚拟地址空间中);您只将整数返回到一些抽象的有限虚拟地址空间。
helloworld922

To help reduce the cost of distributing your implementation the size of the code must be as small as possible还是会尽可能高效(小的和高效的不一样)?:D
编码员

呵呵,语言设计
Akangka '16

尽管这种挑战是由语言设计背景引起的,但设计语言实际上并不是任务的一部分(而是实现其中的一部分),因此我删除了标签。
Martin Ender

Answers:


4

Ruby,80岁

i,a,d=->n{$m=?o*n},->n{$m.sub!(/\B#{?o*n}/,?f*n);"#$`".size},->n,s{$m[n,s]=?o*s}

类似于MegaTom的答案,但是使用字符串而不是数组来存储状态。“ o”字符表示一个开放的单元格,而“ f”字符表示一个填充的单元格。这使我们可以使用Ruby相对简洁的字符串操作函数:

?o*n 初始化n个“ o”的字符串。

/\B#{?o*n}/是匹配不包含第一个字符的n个连续“ o”的正则表达式。 sub!将第一个匹配项替换为n个“ f”。

"#$`" 给出匹配项左侧的字符串,如果没有匹配项,则返回空字符串,因此大小为分配的索引或0。

取消分配只是将字符串的指定部分设置回“ o”。


4

JavaScript(ES6),88

使用全局变量_非常稀疏的数组)进行跟踪。

现在我该如何测试?

I=n=>(_=[1],_[n]=0)
A=n=>_.some((x,i)=>i-p<n?(p=i+x,0):_[p]=n,p=1)?p:0
D=p=>delete _[p]

3

红宝石135

有一个全局数组来跟踪是否分配了每个单元。

i=->n{$a=[!0]*n;$a[0]=0}
a=->n{s=$a.each_cons(n).to_a.index{|a|a.none?};n.times{|i|$a[s+i]=0}if s;s||0}
d=->s,n{n.times{|i|$a[s+i]=!0}}

1

Mathematica,152

i=(n=#;l={{0,1},{#,#}};)&
a=If[#=={},0,l=l~Join~#;#[[1,1]]]&@Cases[l,{Except@n,e_}:>{e,e+#}/;Count[l,{a_,_}/;e<=a<e+#]<1,1,1]&
d=(l=l~DeleteCases~{#,_};)&

n存储总大小,l存储内部状态。分配器将尝试在已分配内存的另一部分后面进行分配。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.