If you look into the source code, you’ll see that `wsample(w)`

calls `sample(default_rng(), weights(w))`

, where `weights(w)`

creates an instance of the mutable `Weights`

. As @Benny pointed out, this allocates.

##
Relevant part of sampling.jl: lines 1044-1056

```
"""
wsample([rng], [a], w)
Select a weighted random sample of size 1 from `a` with probabilities proportional
to the weights given in `w`. If `a` is not present, select a random weight from `w`.
Optionally specify a random number generator `rng` as the first argument
(defaults to `Random.$(VERSION < v"1.3" ? "GLOBAL_RNG" : "default_rng()")`).
"""
wsample(rng::AbstractRNG, w::AbstractVector{<:Real}) = sample(rng, weights(w))
wsample(w::AbstractVector{<:Real}) = wsample(default_rng(), w)
wsample(rng::AbstractRNG, a::AbstractArray, w::AbstractVector{<:Real}) = sample(rng, a, weights(w))
wsample(a::AbstractArray, w::AbstractVector{<:Real}) = wsample(default_rng(), a, w)
```

##
Relevant part of weights.jl: lines 4-23; 69; 82-89

```
"""
@weights name
Generates a new generic weight type with specified `name`, which subtypes `AbstractWeights`
and stores the `values` (`V<:AbstractVector{<:Real}`) and `sum` (`S<:Real`).
"""
macro weights(name)
return quote
mutable struct $name{S<:Real, T<:Real, V<:AbstractVector{T}} <: AbstractWeights{S, T, V}
values::V
sum::S
function $(esc(name)){S, T, V}(values, sum) where {S<:Real, T<:Real, V<:AbstractVector{T}}
isfinite(sum) || throw(ArgumentError("weights cannot contain Inf or NaN values"))
return new{S, T, V}(values, sum)
end
end
$(esc(name))(values::AbstractVector{T}, sum::S) where {S<:Real, T<:Real} = $(esc(name)){S, T, typeof(values)}(values, sum)
$(esc(name))(values::AbstractVector{<:Real}) = $(esc(name))(values, sum(values))
end
end
@weights Weights
"""
weights(vs::AbstractArray{<:Real})
Construct a `Weights` vector from array `vs`.
See the documentation for [`Weights`](@ref) for more details.
"""
weights(vs::AbstractArray{<:Real}) = Weights(vec(vs))
weights(vs::AbstractVector{<:Real}) = Weights(vs)
```

By using `StatsBase.weights(w::Weights) = w`

and directly supplying a `Weights`

to `wsample`

, you skip this instantiation. Note that creating our `Weights`

instance still allocates. But `wsample(w)`

does not if `w is Weights`

.

So to improve your code snippet, you just need to move the `Weights(wts)`

outside of the loop:

```
using Accessors, StaticArrays, StatsBase, BenchmarkTools
StatsBase.weights(w::Weights) = w
function plusone(wghts, res)
for i in 1:100
idx = wsample(wghts)
@reset res[idx] += 1
end
return res
end
wts = @SVector rand(16)
wghts = Weights(wts)
res = @SVector fill(0, 16)
@btime plusone($wghts, $res);
# 2.400 μs (0 allocations: 0 bytes)
```

The reason why @Benny had no allocations in his `@btime wsample(1:16, $(Weights(wts)))`

is because of the interpolation using `$`

. For example,

```
julia> @btime wsample(1:16, $(Weights(wts)));
18.737 ns (0 allocations: 0 bytes)
julia> @btime wsample(1:16, Weights($wts));
30.452 ns (1 allocation: 144 bytes)
julia> @btime $(rand(10^6));
2.200 ns (0 allocations: 0 bytes)
```