# Why does RefValue has allocation?

**URL:** <https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720>\
**Category:** General Usage\
**Tags:** question, gurobi, ref\
**Created:** [February 18, 2026, 9:42am UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720 "2026-02-18T09:42:42Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [February 18, 2026, 9:42am UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720/1 "2026-02-18T09:42:42Z")

</div>

How to explain that only by adding one line `r[]` I had one more allocation? I don’t understand.  
You can neglect the packages, just focus on the function `_grbval` and `grbval`, and `r`. Thanks.

```julia-auto
import JuMP, Gurobi
_grbval(o, x, r) = Gurobi.GRBgetdblattrelement(o, "X", gcc(o, x), r); # calling a C-API
function grbval(o, x, r)
    _grbval(o, x, r)
    getfield(r, :x)
end;

gcc(o, x) = Gurobi.c_column(o, JuMP.index(x));
const r = Ref{Float64}();
const m = JuMP.direct_model(Gurobi.Optimizer());
const o = JuMP.backend(m);
JuMP.@variable(m, x);
JuMP.optimize!(m)
_grbval(o, x, r)
grbval(o, x, r)
@allocated _grbval(o, x, r) # 0
@allocated grbval(o, x, r) # 0
@time _grbval(o, x, r) # 0.000008 seconds
@time grbval(o, x, r) # 0.000010 seconds (1 allocation: 16 bytes)

```

The question is: why does the last line shows there is **1 allocation 16 bytes**.

The definition used in `_grbval` is

```julia-auto
function GRBgetdblattrelement(model, attrname, element, valueP)
    ccall((:GRBgetdblattrelement, libgurobi), Cint, (Ptr{GRBmodel}, Ptr{Cchar}, Cint, Ptr{Cdouble}), model, attrname, element, valueP)
end

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 18, 2026, 10:19am UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720/2 "2026-02-18T10:19:04Z")

</div>

You’re more likely to get help if you make your example as self contained as possible.

You say I can neglect the packages, but they’re pretty intertwined with your example. If I just construct a simple analogue to your example though, I see no such allocations.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [February 18, 2026, 10:56am UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720/3 "2026-02-18T10:56:36Z")

</div>

> [@Mason](#):
>
> If I just construct a simple analogue to your example though, I see no such allocations.

Yes, I cannot reproduce with simple examples either. But mine was indeed a special case.

I think there was already a function barrier, so the `_grbval` function should be a black box, right?

Some related details are

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/f/1f3ed2ea5d7ac836b385074a2b4f48a9ae8b828f.png)

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [February 18, 2026, 11:12am UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720/4 "2026-02-18T11:12:55Z")

</div>

should I conclude that `@time` is misleading, after seeing

```julia-auto
julia> @time grbval(o, x, r)
  0.000010 seconds (1 allocation: 16 bytes)
0.0

julia> using BenchmarkTools

julia> @btime grbval($o, $x, $r)
  38.031 ns (0 allocations: 0 bytes)
0.0

```

?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 18, 2026, 4:02pm UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720/5 "2026-02-18T16:02:14Z")

</div>

A very old section buried in the Perfomance Tips:

> ```julia-auto
> julia> @time sum_arg(x)
> 0.007551 seconds (3.98 k allocations: 200.548 KiB, 99.77% compilation time)
> 523.0007221951678
> 
> julia> @time sum_arg(x)
> 0.000006 seconds (1 allocation: 16 bytes)
> 523.0007221951678
> 
> ```
> 
> The 1 allocation seen is from running the `@time` macro itself in global scope. If we instead run the timing in a function, we can see that indeed no allocations are performed:
> 
> ```julia-auto
> julia> time_sum(x) = @time sum_arg(x);
> 
> julia> time_sum(x)
> 0.000002 seconds
> 523.0007221951678
> 
> ```

You can manually make a forwarding method like `time_sum` to verify that’s the case for your code. `BenchmarkTools` puts the input expression in a function so it has the same effect. Note that despite the exact wording of the section, this extra allocation still shows up in `let` blocks and other (local) scope-introducing blocks except `function`s:

```julia-auto
julia> let; @time sum_arg(x) end
  0.000007 seconds (1 allocation: 16 bytes)
500.0699540425248

```

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [February 19, 2026, 2:02pm UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720/6 "2026-02-19T14:02:50Z")

</div>

Yes, that made sense.

* * *

But I’m still confused here:

```julia-auto
julia> f() = Ref{Cdouble}();

julia> tf() = @time f();

julia> tf()
  0.000000 seconds (1 allocation: 16 bytes)
Base.RefValue{Float64}(0.0)

julia> tf()
  0.000000 seconds (1 allocation: 16 bytes)
Base.RefValue{Float64}(0.0)

julia> using BenchmarkTools

julia> @btime f()
  8.560 ns (1 allocation: 16 bytes)
Base.RefValue{Float64}(6.41014581546824e-310)

julia> @allocated f()
0

```

My question is: Does the `Ref{Cdouble}()` action entails allocation or not?

My practical usage is the following 3-line function, in which `r` is a temporary object

```julia-auto
function get_from_C_API()
    r = Ref{Cdouble}()
    a_C_api!(r) # fill in its value
    getfield(r, :x)
end

```

I wonder if this function has allocation or not when it is executed. Can the compiler optimize it so that there is 0 allocation?

* * *

I have no idea which helper macro should I trust, e.g. this example

```julia-auto
julia> function f(x)
           r = Ref{Cdouble}()
           r.x > -9e100 && setindex!(x, 0, 1)
           r.x
       end
f (generic function with 1 method)

julia> x = [1];

julia> @allocated f(x)
0

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [February 20, 2026, 1:56am UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720/7 "2026-02-20T01:56:31Z")

</div>

> [@WalterMadelim](#):
>
> My question is: Does the `Ref{Cdouble}()` action entails allocation or not?

Yes and no, depending on the context:

```julia-auto
julia> @code_llvm f()

```

```llvm
; Function Signature: f()
; @ REPL[1]:1 within `f`
define nonnull ptr @julia_f_3678() local_unnamed_addr #0 {
top:
  %pgcstack = call ptr inttoptr (i64 4315955464 to ptr)(i64 4315955500) #7
; ┌ @ refpointer.jl:146 within `Ref`
; │┌ @ refvalue.jl:7 within `RefValue`
    %ptls_field = getelementptr inbounds nuw i8, ptr %pgcstack, i64 16
    %ptls_load = load ptr, ptr %ptls_field, align 8
    %"new::RefValue" = call noalias nonnull align 8 dereferenceable(16) ptr @ijl_gc_small_alloc(ptr %ptls_load, i32 424, i32 16, i64 4642896336) #4
    %"new::RefValue.tag_addr" = getelementptr inbounds i8, ptr %"new::RefValue", i64 -8
    store atomic i64 4642896336, ptr %"new::RefValue.tag_addr" unordered, align 8
    ret ptr %"new::RefValue"
; └└
}

```

See the `@ijl_gc_small_alloc`? That’s a memory allocation.

```julia-auto
julia> @macroexpand @allocated f()
quote
    #= timing.jl:561 =#
    $(Expr(:meta, :force_compile))
    #= timing.jl:562 =#
    Base.allocated(f)
end

julia> @code_llvm Base.allocated(f)

```

```llvm
; Function Signature: allocated(typeof(Main.f))
; @ timing.jl:517 within `allocated`
define i64 @julia_allocated_4009() local_unnamed_addr #0 {
top:
; @ timing.jl:518 within `allocated`
; ┌ @ refpointer.jl:147 within `Ref`
; │┌ @ refvalue.jl:8 within `RefValue`
    %"new::RefValue" = alloca i64, align 16
; └└
; @ timing.jl:519 within `allocated`
; ┌ @ refpointer.jl:147 within `Ref`
; │┌ @ refvalue.jl:8 within `RefValue`
    %"new::RefValue4" = alloca i64, align 16
    call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %"new::RefValue")
; └└
; @ timing.jl:518 within `allocated`
; ┌ @ refpointer.jl:147 within `Ref`
; │┌ @ refvalue.jl:8 within `RefValue`
    store i64 0, ptr %"new::RefValue", align 16
    call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %"new::RefValue4")
; └└
; @ timing.jl:519 within `allocated`
; ┌ @ refpointer.jl:147 within `Ref`
; │┌ @ refvalue.jl:8 within `RefValue`
    store i64 0, ptr %"new::RefValue4", align 16
; └└
; @ timing.jl:520 within `allocated`
; ┌ @ timing.jl:509 within `gc_bytes`
   call void @jlplt_ijl_gc_get_total_bytes_4013_got.jit(ptr nonnull %"new::RefValue")
; └
; @ timing.jl:522 within `allocated`
; ┌ @ timing.jl:509 within `gc_bytes`
   call void @jlplt_ijl_gc_get_total_bytes_4013_got.jit(ptr nonnull %"new::RefValue4")
; └
; @ timing.jl:523 within `allocated`
; ┌ @ refvalue.jl:59 within `getindex`
; │┌ @ Base_compiler.jl:57 within `getproperty`
    %"new::RefValue4.x" = load i64, ptr %"new::RefValue4", align 8
    %"new::RefValue.x" = load i64, ptr %"new::RefValue", align 8
; └└
; ┌ @ int.jl:86 within `-`
   %0 = sub i64 %"new::RefValue4.x", %"new::RefValue.x"
; └
  ret i64 %0
}

```

`@allocated f()` is actually calling `Base.allocated(f)`, and inside that function the compiler replaced the heap allocation with a stack-based [`alloca`](https://llvm.org/docs/LangRef.html#alloca-instruction)

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [February 20, 2026, 8:57am UTC](https://discourse.julialang.org/t/why-does-refvalue-has-allocation/135720/8 "2026-02-20T08:57:44Z")

</div>

The problem with benchmarking small “isolated” code snippets is that they’re isolated. They may behave differently when inlined somehwere else, or constants are propagated, or something, and the compiler finds or loses opportunities for optimizing.
