# Gc and resize!

**URL:** <https://discourse.julialang.org/t/gc-and-resize/18374>\
**Category:** General Usage\
**Tags:** question\
**Created:** [December 6, 2018, 1:00pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374 "2018-12-06T13:00:54Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 6, 2018, 1:00pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/1 "2018-12-06T13:00:54Z")

</div>

I have a stream of values, from which I collect blocks of values depending on some criterion which is calculated online, so I don’t know the size of a block until the last element. Then I process each block.

Since I know the type of values, I would like to pre-allocate a buffer while collecting to minimize allocations. Apparently `resize!(buffer, 0)` and `push!(buffer, elt)` result in very few allocations for the MWE below, the question is

1. whether this is the right idiom, or if there is a better one,
2. can I rely on the memory for `buffer` not being `gc`d between two blocks?

MWE (heavily simplified, actual problem is more complex):

```julia
mutable struct Source
    i::Int
end

Source() = Source(0)

get_element(s::Source) = s.i += 1

Base.eltype(::Type{Source}) = Int

function get_block!(buffer, source)
    resize!(buffer, 0)
    for _ in 1:rand(5:10)
        push!(buffer, get_element(source))
    end
end

process_block(buffer) = sum(abs, buffer)

function process_blocks(source, n)
    buffer = Vector{eltype(source)}()
    sum((get_block!(buffer, source); process_block(buffer)) for _ in 1:n)
end

```

then

```julia
julia> @time process_blocks(Source(), 100000);
  0.014218 seconds (12 allocations: 608 bytes)

```

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [December 6, 2018, 2:20pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/2 "2018-12-06T14:20:14Z")

</div>

I don’t see any memory being freed [in the source](https://github.com/JuliaLang/julia/blob/master/src/array.c#L1025) called for `resize!`, so this seems like a good way to do it if you don’t mind relying on undocumented behavior. (If you depend on this, perhaps add proper documentation and a unit test that ensures that memory is not re-allocated, so that you’ll be notified if this behavior ever changes.)

Alternatively, at least in the example here, it seems like it’d be fairly easy to keep track of the buffer size yourself, and overwrite existing entries if there’s room, and grow it otherwise. You could create a simple wrapper type around a `Vector` to support this.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 6, 2018, 2:34pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/3 "2018-12-06T14:34:05Z")

</div>

> [@bennedich](#):
>
> a unit test that ensures that memory is not re-allocated

I am not sure how one could test for this without exposing internals.

Also, I am totally OK with the GC reallocating `buffer` occasionally, especially if it grew to big for a single occasion, as long as it does not happen 99% of the time. Which seems to be the case.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [December 6, 2018, 3:23pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/4 "2018-12-06T15:23:56Z")

</div>

`resize!(buffer, 0)` does not free the buffer. If you want to free it, do `resize!(buffer, 0); sizehint!(buffer, 0)`.

So your construction is exactly right.

If your buffer contains bitstypes and the collecting turns out to be a bottleneck, then consider not using `push!`. This is because `push!` is currently not inlining the fast path (enough capacity in the buffer underlying the `Vector`), and hence has an overhead of a handful cycles (call into the runtime). In that case, you can use e.g.

```julia
function get_block2!(buffer, source)
    cnt = 0
    if length(buffer)<10
        resize!(buffer, 10)
    end
    for elem in source
        cnt += 1
        if length(buffer)< cnt
             resize!(buffer, 2*length(buffer))
        end
        @inbounds buffer[cnt] = elem
    end
    return cnt
end

```

assuming that your source obeys the iteration protocol and does not know how many elements it will collect. If your don’t use bitstypes, then you could use

```julia
function get_block3!(buffer, source, capa)
    cnt = 0
    resize!(buffer, max(capa, 10))
    for elem in source
        cnt += 1
        if length(buffer)< cnt
             resize!(buffer, 2*capa)
             capa = 2*capa
        end
        @inbounds buffer[cnt] = elem
    end
    resize!(buffer, cnt)
    return capa
end

```

The initial resize is within capacity and only zeros the memory.

PS. Just for comparison:

```julia
julia> using BenchmarkTools
julia> buf=Float64[]; src=rand(10_000);
julia> function get_block!(buffer, source)
           resize!(buffer, 0)
           for elem in source
               push!(buffer, elem)
           end
           end
julia> @btime get_block!($buf, $src);
  69.774 μs (0 allocations: 0 bytes)

julia> @btime get_block2!($buf, $src);
  15.424 μs (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [December 6, 2018, 6:12pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/5 "2018-12-06T18:12:45Z")

</div>

There is also the “PushVector” that does this but with a perhaps nicer interface:

[https://github.com/JuliaLang/julia/issues/24909#issuecomment-419731925](https://github.com/JuliaLang/julia/issues/24909#issuecomment-419731925)

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 6, 2018, 6:48pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/6 "2018-12-06T18:48:18Z")

</div>

Neat. I wonder if it would make sense to factor out `PushVector` to a mini-package. I don’t know what the timeline is for fixing #24909.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [December 6, 2018, 6:51pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/7 "2018-12-06T18:51:10Z")

</div>

Special handling of `push!` in codegen might be possible to basically emit the code the `PushVector` does (but of course using the `capacity` field in the `jl_array` struct.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [December 6, 2018, 7:08pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/8 "2018-12-06T19:08:10Z")

</div>

Ok, I really should try to make a PR to inline the `push!` fastpath; yuyichao patiently explained to me how to do it (surprisingly non-terrible, but I’m new to codegen). This problem crops up all the time.

That will, however, still be slower than `get_block2!`: `cnt` can be kept in register (which means that `buffer` will be in an indefinite state if you need to recover from an exception, because nobody remembered `cnt`) as opposed to updating a single int (`PushVector`) or two ints (forcibly inlined `ccall(:jl_array_grow_end, ...)` updates both `length(buf)` and `size(buf,1)` because, for some reason, both are stored in vectors). Also, it may require a little fiddling to be friendly for hoisting the flag-checks (somebody could unfairly use a `reshape` to make our `buffer` unresizable).

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [December 6, 2018, 9:51pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/9 "2018-12-06T21:51:26Z")

</div>

> [@Tamas\_Papp](#):
>
> I am not sure how one could test for this without exposing internals.

Mock objects, or simply a specific test that `resize!` + `push!` doesn’t allocate, if that’s your concern.

> [@Tamas\_Papp](#):
>
> I am totally OK with the GC reallocating `buffer` occasionally, especially if it grew to big for a single occasion, as long as it does not happen 99% of the time.

It currently happens 0 % of the time (even for big buffers, if I’m reading the source correctly). My concern, from a long term maintainable code perspective, would rather be if the implementation ever changes in the future.

> [@foobar\_lv2](#):
>
> `resize!(buffer, 0)` does not free the buffer

From the [C source](https://github.com/JuliaLang/julia/blob/master/src/array.c#L1025) we can tell that this is the case, but [the documentation](https://docs.julialang.org/en/v1/base/collections/#Base.resize!) doesn’t promise it. So can we rely on it? (If so, we should update the doc.)

> [@kristoffer.carlsson](#):
>
> There is also the “PushVector” that does this but with a perhaps nicer interface

This is precisely what I had in mind with “a simple wrapper”, thanks for saving me the typing 🙂 Although, in lieu of `finish!` I was thinking:

```julia
unsafe_wrap(Array, pointer(buf), length)

```

(or is this bad practice?)

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [December 6, 2018, 9:59pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/10 "2018-12-06T21:59:50Z")

</div>

> [@bennedich](#):
>
> (or is this bad practice?)

yes 🙂

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [December 6, 2018, 10:12pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/11 "2018-12-06T22:12:13Z")

</div>

> [@kristoffer.carlsson](#):
>
> yes 🙂

May I ask why, if you control the buffer? I’ve seen it used in several places in the source for Julia itself.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [December 6, 2018, 10:19pm UTC](https://discourse.julialang.org/t/gc-and-resize/18374/12 "2018-12-06T22:19:04Z")

</div>

In my code the `PushVector` itself allocates the buffer so we do not control it. Even if we control it the compiler can optimize things away and unless we have a `GC.@preserve` it is hard to know the lifetime of `buffer`. Anyway, it is bad practice to use `unsafe_` if you don’t need it, doesn’t seem like it is needed here.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 7, 2018, 9:59am UTC](https://discourse.julialang.org/t/gc-and-resize/18374/13 "2018-12-07T09:59:25Z")

</div>

> [@foobar\_lv2](#):
>
> I really should try to make a PR to inline the `push!` fastpath

That would be great.
