# Unexpected memory allocation behavior

**URL:** <https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922>\
**Category:** General Usage\
**Tags:** memory-allocation\
**Created:** [January 2, 2022, 10:40am UTC](https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922 "2022-01-02T10:40:40Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Siddharth\_Bhatia](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/siddharth_bhatia/32/12130_2.png) [@Siddharth\_Bhatia](https://discourse.julialang.org/u/Siddharth_Bhatia)\
**Post date:** [January 2, 2022, 10:40am UTC](https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922/1 "2022-01-02T10:40:40Z")

</div>

Hello. I am using julia `1.7.1`.

I am facing trouble trying to understand an unexpected memory allocation in the below simplified and self-contained program:

```julia
struct VerticalLine{I}
    i_min::I
    i_max::I
    j::I
end

struct ParallelVerticalLines{I}
    i::I
    j::I
    height::I
    width::I
end

function put_pixel!(image::AbstractMatrix, i, j, color)
    image[i, j] = color
    return nothing
end

function draw!(f::Function, image::AbstractMatrix, shape::VerticalLine, color)
    i_min = shape.i_min
    i_max = shape.i_max
    j = shape.j

    for i in i_min:i_max
        f(image, i, j, color)
    end

    return nothing
end

function draw!(f::Function, image::AbstractMatrix, shape::ParallelVerticalLines, color)
    i_min = shape.i
    i_max = shape.i + shape.height - one(shape.height)
    # i_max = shape.i

    j_min = shape.j
    j_max = shape.j + shape.width - one(shape.width)
    # j_max = shape.j

    shape1 = VerticalLine(i_min, i_max, j_min)
    draw!(f, image, shape1, color)

    shape2 = VerticalLine(i_min, i_max, j_max)
    draw!(f, image, shape2, color)

    return nothing
end

const shape = ParallelVerticalLines(1, 1, 3, 3)

const image1 = zeros(UInt32, 32, 32)
const color1 = 0x00ffffff

draw!(put_pixel!, image1, shape, color1)

println(@allocated draw!(put_pixel!, image1, shape, color1))

const image2 = falses(32, 32)
const color2 = true

draw!(put_pixel!, image2, shape, color2)

println(@allocated draw!(put_pixel!, image2, shape, color2))

```

Here are my observations that are puzzling to me:

1. The `draw!` function allocates memory in the `UInt32` case but not in the `Bool` case.
2. When I comment out `i_max = shape.i + shape.height - one(shape.height)` and `j_max = shape.j + shape.width - one(shape.width)`, and replace them with `i_max = shape.i` and `j_max = shape.j` respectively, the memory allocation vanishes.
3. When I comment out `shape2 = VerticalLine(i_min, i_max, j_max)` and `draw!(f, image, shape2, color)`, the memory allocation again vanishes.
4. `@code_warntype draw!(put_pixel!, image1, VerticalLine(1, 3, 1), color1)` and `@code_warntype draw!(put_pixel!, image2, VerticalLine(1, 3, 1), color2)` have a `Union` type inferred for an automatically named local variable. I don’t understand what this local variable is and why it is not inferred correctly.

`@code_warntype draw!(put_pixel!, image1, shape, color1)` and `@code_warntype draw!(put_pixel!, image2, shape, color2)` shows that all types seem to be inferred. I don’t see any obvious type instability that might be causing the above issues.

It would be great if someone could help me explain the reasons behind my observations. Thanks!

Here is the output of `versioninfo()`, if needed:

```julia
julia> versioninfo()
Julia Version 1.7.1
Commit ac5cc99908 (2021-12-22 19:35 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, skylake)

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 2, 2022, 12:19pm UTC](https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922/2 "2022-01-02T12:19:08Z")

</div>

> [@Siddharth\_Bhatia](#):
>
> `function draw!(f::F, image::AbstractMatrix, shape::ParallelVerticalLines, color) where F`

Try the above, because of

[https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing)

(didn’t test)

---

<div class="post-metadata">

**Author:** ![Bardo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bardo/32/21601_2.png) [@Bardo](https://discourse.julialang.org/u/Bardo)\
**Post date:** [January 2, 2022, 12:53pm UTC](https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922/3 "2022-01-02T12:53:05Z")

</div>

I get a warning because you define `image1` and `image2` as `const` and later assign values to them. Removing the `const` changes the picture, both allocate

```julia
  340.092 ns (4 allocations: 96 bytes)
  321.888 ns (2 allocations: 64 bytes)

```

Still puzzling why the number of allocations changes, same for the number of bytes in relation to UInt32 and Bool.

---

<div class="post-metadata">

**Author:** ![Siddharth\_Bhatia](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/siddharth_bhatia/32/12130_2.png) [@Siddharth\_Bhatia](https://discourse.julialang.org/u/Siddharth_Bhatia)\
**Post date:** [January 2, 2022, 2:42pm UTC](https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922/4 "2022-01-02T14:42:29Z")

</div>

Thanks a lot for your help @lmiq ! Doing as you suggested doesn’t allocate any memory.

---

<div class="post-metadata">

**Author:** ![Siddharth\_Bhatia](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/siddharth_bhatia/32/12130_2.png) [@Siddharth\_Bhatia](https://discourse.julialang.org/u/Siddharth_Bhatia)\
**Post date:** [January 2, 2022, 2:49pm UTC](https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922/5 "2022-01-02T14:49:55Z")

</div>

Hello @Bardo , I am running the program as a script, where I do not get the warning you mention. The warning might occur in case you include the script more than once in the REPL.

> [@Bardo](#):
>
> you define `image1` and `image2` as `const` and later assign values to them.

I am only assigning `image1` and `image2` once in the script, and that is while defining them.

---

<div class="post-metadata">

**Author:** ![Bardo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bardo/32/21601_2.png) [@Bardo](https://discourse.julialang.org/u/Bardo)\
**Post date:** [January 2, 2022, 4:43pm UTC](https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922/6 "2022-01-02T16:43:39Z")

</div>

> [@Siddharth\_Bhatia](#):
>
> The warning might occur in case you include the script more than once in the REPL.

Bingo.

@lmiq How does your type hint help here? - `F` is not used elsewhere.  
How could one have found this solution?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 2, 2022, 5:36pm UTC](https://discourse.julialang.org/t/unexpected-memory-allocation-behavior/73922/7 "2022-01-02T17:36:46Z")

</div>

> [@Bardo](#):
>
> How does your type hint help here? - `F` is not used elsewhere.  
> How could one have found this solution?

I found that not long time ago by [asking something similar here](https://discourse.julialang.org/t/allocations-when-passing-closure-as-parameter/63082) (but it is on the performance tips, as I llinked above).

That is a special case of non-specialization: the function is just passed around to another function. Since functions have each their own type, having a specialized method (a whole compilation) for each type of function would be counter-productive. Thus, the default is to not specialize, and that probably boxes the function, creating the allocation. In terms of performance that is probably harmless, unless in very special cases where the function is passed around to another function within a critical loop (and even there, I don’t think it had a measurable performance penalty in my case). But, if one _wants_ the function to specialize to every different type of function input, the parameterization of the type (`::F where F` syntax) is a way to force that, and it is fine except if the use case expects many different functions to be passed around.
