slice of pointers, slicing and gc

465 views
Skip to first unread message

ahme...@hotmail.de

unread,
Oct 18, 2015, 3:04:02 PM10/18/15
to golang-nuts
Hello folks,

I have a questions about slices of pointer:

I have slice of pointer  of structs  and I want to cut off an element using append.
The element(s) I want to cut off are no longer needed and can be deleted freed by the gc.

a = make([]*T, n)

for i = 0; i < n; i++ {
     a[i] = *T{}
}
a = append(a[:i], a[j:])

What do I have to consider, to do, to prevent memory leak?

Thanks for your help

Nodir Turakulov

unread,
Oct 18, 2015, 4:11:39 PM10/18/15
to ahme...@hotmail.de, golang-nuts
I think you have to clear memory, otherwise the items won't be GCed:

for i := j; i < len(a); i++ {
  a[i] = nil
}

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nodir Turakulov

unread,
Oct 18, 2015, 4:30:23 PM10/18/15
to ahme...@hotmail.de, golang-nuts
I meant

a = append(a[:i], a[i+1:]...)
a[len(a):len(a)+1][0] = nil

This clears the item a[len(a)]

ahme...@hotmail.de

unread,
Oct 18, 2015, 4:45:47 PM10/18/15
to golang-nuts, ahme...@hotmail.de
I'm sorry, could you please explain what you did?
Is this a 2D slice?


a[len(a):len(a)+1][0] = nil

or what are you doing there?

Roberto Zanotto

unread,
Oct 18, 2015, 4:58:06 PM10/18/15
to golang-nuts, ahme...@hotmail.de

Nodir Turakulov

unread,
Oct 18, 2015, 5:17:11 PM10/18/15
to Roberto Zanotto, golang-nuts, ahme...@hotmail.de
From the link provided by Roberto,
a, a[len(a)-1] = append(a[:i], a[i+1:]...), nil

is what you need. It is a more elegant version of what I've suggested.

a[len(a):len(a)+1] creates a slice that starts with the element that needs to be cleared, and then ...[0]=nil clears the element.

ahme...@hotmail.de

unread,
Oct 18, 2015, 7:15:33 PM10/18/15
to golang-nuts, roby...@gmail.com, ahme...@hotmail.de
Could you please, explain what there happens step by step. I think I have a leak in understanding here.

Nodir Turakulov

unread,
Oct 18, 2015, 7:35:13 PM10/18/15
to ahme...@hotmail.de, golang-nuts, roby...@gmail.com
Statement

  a, a[len(a)-1] = append(a[:i], a[i+1:]...), nil

is a second form of tuple assignment. It proceeds in two phases. 

First, the operands of index expressions on the left and the expressions on the right are all evaluated in the usual order. That is, it is equivalent to
  lhs2_1 := a
  lhs2_2 := len(a) - 1
  rhs1 := append(a[:i], a[i+1:]...)
  rh2 := nil

here append(a[:i], a[i+1:]...) creates a new slice of the a's underlying array, with length len(a)-1 and with items started from i+1 shifted left.

In the second phase of the assignment, the following happens:

  a = rhs1
  lhs2_1[lhs2_2] = rhs2

which
1) assigns a shirked slice to a 
2) sets the last item of the original a to nil

This trick relies on the behavior of the tuple assignment.

Roberto Zanotto

unread,
Oct 18, 2015, 8:22:34 PM10/18/15
to golang-nuts, ahme...@hotmail.de
Just to be sure, is the order of the elements in the array important? Because it's more simple and less expensive to delete an element if you are allowed to swap them. To delete element "i", you could overwrite it with a copy of the last element and then delete the last one:
last := len(a) - 1 // index of the last element
a[i] = a[last]
a[last] = nil
a = a[:last]


On Sunday, October 18, 2015 at 9:04:02 PM UTC+2, ahme...@hotmail.de wrote:

ahme...@hotmail.de

unread,
Oct 19, 2015, 2:05:20 AM10/19/15
to golang-nuts, ahme...@hotmail.de
Good I have understand this part.
Now a resulting question:

a, a[len(a)-1] = append(a[:i], a[i+1:]...), nil

after this operation. What will happen to the "old slice a"??
Because append makes a new slice. Will the GC delete the old slice elements? When yes?
Why do I have to set the slice entry nil?

Dave Cheney

unread,
Oct 19, 2015, 2:27:35 AM10/19/15
to golang-nuts
The backing array for a is still in use, it's length has just been reduced by one, masking off the final element. The reason you nil the final elegant is otherwise it will still be reachable from a.

a -> backingarray[last element] -> value

Nodir Turakulov

unread,
Oct 19, 2015, 4:10:15 AM10/19/15
to Dave Cheney, golang-nuts

To clarify: the length of the slice has been reduced, not the length of the array.


On Sun, Oct 18, 2015, 11:27 PM Dave Cheney <da...@cheney.net> wrote:
The backing array for a is still in use, it's length has just been reduced by one, masking off the final element. The reason you nil the final elegant is otherwise it will still be reachable from a.

a -> backingarray[last element] -> value

ahme...@hotmail.de

unread,
Oct 19, 2015, 5:22:47 AM10/19/15
to golang-nuts, da...@cheney.net
But why people say, when using append, that it not clear, if a new slice is created or the old one modified?

Nodir Turakulov

unread,
Oct 19, 2015, 11:33:01 AM10/19/15
to ahme...@hotmail.de, golang-nuts, da...@cheney.net

A slice is just a pointer to an array element with some extra attributes. Creating a slice on the same array is cheap.

Append always creates a new slice, but most of the time it reuses the array, so usually it is cheap.

See http://golang.org/blog/go-slices-usage-and-internals

ahme...@hotmail.de

unread,
Oct 19, 2015, 12:56:57 PM10/19/15
to golang-nuts, ahme...@hotmail.de, da...@cheney.net
So it is possible, that sometimes a memory leak happens?

Tamás Gulácsi

unread,
Oct 19, 2015, 1:13:42 PM10/19/15
to golang-nuts, ahme...@hotmail.de, da...@cheney.net

2015. október 19., hétfő 18:56:57 UTC+2 időpontban ahme...@hotmail.de a következőt írta:
So it is possible, that sometimes a memory leak happens?

No memory leak, just some CPU time, as append copies the slice's live elements into the new slice when allocates a new slice.

Konstantin Khomoutov

unread,
Oct 19, 2015, 1:23:37 PM10/19/15
to ahme...@hotmail.de, golang-nuts, da...@cheney.net
On Mon, 19 Oct 2015 09:56:32 -0700 (PDT)
ahme...@hotmail.de wrote:

> So it is possible, that sometimes a memory leak happens?

If you were alarmed by that "most of the time" bit, please don't:
the backing array might not be reused only when append() operating
on the slice pointing into that array is requested to *grow* the slice
beyond the size of the underlying array.
Shrinking a slice won't reallocate its backing array, and this is
detailed in the "Possible gotchas" section of the article linked,
and it's really advised to read it.

> Am Montag, 19. Oktober 2015 17:33:01 UTC+2 schrieb Nodir Turakulov:
> >
> > A slice is just a pointer to an array element with some extra
> > attributes. Creating a slice on the same array is cheap.
> >
> > Append always creates a new slice, but most of the time it reuses
> > the array, so usually it is cheap.
> >
> > See http://golang.org/blog/go-slices-usage-and-internals
[...]

ahme...@hotmail.de

unread,
Oct 19, 2015, 2:24:44 PM10/19/15
to golang-nuts, ahme...@hotmail.de
I'm very thankful for you patience. You helped me well!
Reply all
Reply to author
Forward
0 new messages