13

I'm 4 days old in Java and from the tutorials I've searched, the instructors focus a lot of effort in explaining how to allocate a two dimensional array (e.g.) as such:

Foo[][] fooArray = new Foo[2][3];

... but I've not found any that explains how to delete them.

From what is going on memory-wise, the variable fooArray will point to a block of memory in the heap, in which there are 2 elements. Each of the elements points to another block in the heap as well, which have 3 elements.

That being said, could I just reference the first block of elements and the garbage collector will do the job?

Foo[1] = null; and Foo[2] = null;

Or do I have to null each of the instantiated Foo elements?

Foo[1][1] = null; Foo[1][2] = null; Foo[1][3] = null; ...

Jason
  • 11,744
  • 3
  • 42
  • 46
Chronus
  • 365
  • 3
  • 10
  • 1
    @TT. although the answer is the same, my question was specific in arrays. Meaning that, even if I've read it before I asking, I would still be in doubt (from a nooby perspective) – Chronus Apr 08 '19 at 07:38
  • 5
    Ok I hear you. Know that everything apart from primitive data types (e.g. int, double, ...) are objects. Important to know. – TT. Apr 08 '19 at 07:49

3 Answers3

17

Explanation

You can not explicitly delete something in Java. It is the garbage collectors job to do that. It will delete anything which is not used anymore by anyone. So either

  1. let the variable fall out of scope or
  2. assign null
  3. or any other instance to it.

Then the array instance (as well as its subarrays) is not referenced anymore and the garbage collector will delete it eventually.


References

To understand why re-assigning the outer array is enough to also delete the inner arrays, you need to understand how they are referenced. Again, the garbage collector can delete anything which is unreachable. So let's take a look at an array such as:

int[][] outer = {{1, 2}, {3, 4}, {5, 6}};

We have 4 array instances. One is of type int[][] and three of type int[]. Also, we have one variable outer. The instances are referenced as follows:

                       ___> {1, 2}
                      |
outer  --> int[][] ---|---> {3, 4}
                      |
                      |___> {5, 6}

So by deleting outer, nobody references int[][] anymore. The garbage collector can now delete it. But that also removes all references to the inner arrays, so the garbage collector can now also delete them.

Now assume that you would reference one of the inner arrays by another variable:

int[][] outer = {{1, 2}, {3, 4}, {5, 6}};
int[] thirdInner = outer[2];
other = null; // remove the reference

The situation is now

outer  --> null

                       ___> {1, 2}
                      |
           int[][] ---|---> {3, 4}
                      |
                      |______> {5, 6}
                          |
thirdInner _______________|

So the garbage collector will now delete the outer array int[][], which also removes all references to the first and second inner array. But the third is still referenced by thirdInner, so after garbage collection we have:

outer       --> null
thirdInner  --> {5, 6}
Holger
  • 285,553
  • 42
  • 434
  • 765
Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • 3
    "Not referenced" is tricky - as everything is "not referenced" at some point. The correct language is "not reachable by hard references from a GC root". – Boris the Spider Apr 08 '19 at 10:26
  • That's absolute correct and a good note! But I feel that it would unnecessarily complicate the answer. – Zabuzard Apr 08 '19 at 10:34
  • @BoristheSpider I think "not referenced" is a good choice of words, as everything is referenced in java, just possibly not necessarily from java objects but from the jvm internals (e.g. stack variables, loaded java.lang.Class instances, ...) (the latter cases being marked together as GC roots). So I'd still call it "referenced". – bwoebi Apr 08 '19 at 12:25
  • 2
    "Not referenced" is not strictly correct. "Not referenced" implies that two objects which refer to each other, or one object which refers to itself, won't be deleted, which is obviously untrue. Garbage collectors don't delete objects that are "not referenced", they delete objects that are not **reachable** from a GC root (running thread). When `null` is assigned to `outer`, the entire array and all inner arrays become not **reachable** by the program, and all are swept away in one go. It's not necessary to delete the outer array first, in order to discover the inner arrays were also deletable. – Boann Apr 08 '19 at 16:34
  • ^ this. That's why the terminology used is problematic and could in fact cause more confusion. – Boris the Spider Apr 10 '19 at 06:22
  • 1
    Be my guest and correct the terms. But I think it is better to keep it simple and then add a section which has a reference to some deeper explanation, quickly summarizing how it works in two sentences. – Zabuzard Apr 10 '19 at 07:12
  • 2
    The phrase is fine for the first, introductory part, but I edited the sentence in the second part, as it’s helpful for readers when the terminology matches what can be found in other literature (if they are interested in more details). I also added a link to the specification. And I think it’s important to say “can” rather than “will”, as garbage collection is intentionally non-deterministic. Actually, not even the term “delete” matches what is really going on, but I think, it’s better to keep it this way, as there is enough further reading out there. – Holger Apr 12 '19 at 07:41
13

At some point after the array goes out of scope, the garbage collector will reclaim the memory if there are no other references to it.

If you want to null your reference before the variable goes out of scope (keep in mind that if some other code has this reference, it won't get garbage collected):

Foo[][] fooArray = new Foo[2][3];

...

// this will null the reference to the array
fooArray = null;
Jason
  • 11,744
  • 3
  • 42
  • 46
  • 3
    Your phrasing (“once”) makes it sounds as if the memory will be reclaimed *as soon as* the last reference goes out of scope. It’s a rather important property of the Java GC that *this is not the case*. – Konrad Rudolph Apr 08 '19 at 09:24
  • Good point - edited. – Jason Apr 08 '19 at 22:24
2

Unlike C, Java provides automatic garbage collection,which will clear the array for you as it becomes unreachable(i.e goes out of scope).If you want you can make the array as null so that the memory location becomes unreachable.

    Foo[][] fooArray = new Foo[2][3];
    .
    .
    .
    fooArray = null;
    System.gc();

This gc call doesn't ensure that JVM will run garbage collector but it suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects

Vaibhav Gupta
  • 638
  • 4
  • 12
  • 4
    I do not really see the benefit of suggesting `System#gc`. In most situations it will degrade performance. Let the garbage collector do it's job. It is usually only used to cleanup before a measurement (profiler and other tools). – Zabuzard Apr 08 '19 at 07:15
  • I agree with you but in some cases, it may make sense to suggest to the JVM that it do a full collection NOW as you may know the application will be sitting idle for the next few minutes before heavy work – Vaibhav Gupta Apr 08 '19 at 07:18
  • 5
    @Vaibhav Gupta The garbage collector does not **clear** the array, it only frees it. It is possible for malware to access the data, sometimes for a long time, until the memory has been reused. If the array contains sensitive data it should be actively cleared before being released. – Jonathan Rosenne Apr 08 '19 at 07:52