Memory management: how to reset the list correctly

Regarding the memory used and the impact on the garbage collector, I would like to know if there is a difference between the two implementations:

protected List<T> _data = new ArrayList<T>(); // I want to reset this list using another one. First try : public void set(List<T> newData) { _data = newData; } // I want to reset this list using another one. Second try : public void set(List<T> newData) { _data.clear(); _data.addAll(newData); } 

Also, if there is any functional difference, please tell me!

+6
source share
6 answers

The first letter simply replaces its link to the list with those provided by the callers. If the old list is not available anywhere, it is entitled to GC.

The second uses the existing list of objects and copies into it all the links to the elements of the caller list. If this increases the size of the collection, then this may include allocating a larger array from the inside (which makes assembling a smaller array).

The reachability of the objects themselves does not change; both versions force lists to refer to the same elements.

The first is usually pretty fast, since you are replacing one link. This works less than copying a bunch of links from one list to another.

Secondly, although it is usually better in terms of encapsulation. Imagine this ...

 yourThingie.set(myItems); myItems.add(objectYouNeverWouldHaveAllowed); 

In the first version, _data now contains objectYouNeverWouldHaveAllowed . You can no longer apply class restrictions on _data ; since you let the caller bring their own list there, they now have control over the internal state of your property. They can tear your object apart, even by accident.

The second one has no such problem. You retain control of _data , subsequent changes to the caller in their list do not affect you, and if you do not do something broken (for example, provide the recipient who retrieves the naked object), you are safe.

+3
source

The first example replaces the old object with the new one. This is normal if you create a new list each time. If your set () needs to take a copy of the list because it can be modified by the caller, a second example can be considered.

Second example: list reuse, and it could be

  • good as it saves making the copy.
  • Bad, because you can have an object in space that refers to many young objects. If this is enough, it will slow down the GC time.

In general, you should do what you think is the easiest solution and worry about performance when you measure your application, for example. with memory profiler. and this suggests that you have a problem. If you are not measuring, you are just guessing.

AFAIK, Java JVM does not support reference counting for memory management. If this is not prohibited by the standard, but there are too many problems to consider using it in Java. For example, circular links. An interesting fact, smart pointers in C ++ use reference counting :(

+3
source

I would just use the first method in which you used _data = newData; . _data is a pointer to a list. So by doing this, you will make _data point to newData. Since everything that was mentioned earlier by _data is no longer mentioned, then the garbage collector will get rid of it.

However, your second method is quite expensive, and I would not do that. Yes, it does the same, but instead of just moving the pointer, it does more calculations that will cost you.

0
source

According to the docs, this is what clear() does:

 public void clear() { modCount++; for (int i = 0; i < size; i++) elementData[i] = null; size = 0; } 

So, I believe that creating a new List will actually be faster (when the size of the list is too large), but I'm not sure that it will make it more efficient in terms of memory usage.

Sometimes efficiency is not only related to speed.

0
source

The first is one link job. The second is to copy the list of links from "newData" to "_event", possibly changing the size of "_event" in this process, which entails further copying.

BUT ... "Premature optimization, if the root of all evil." (If it doesn't ring, find it!)

The semantic difference is probably more important in most cases. In the first, you simply refer to the data provided by "set" - if the call code subsequently changes it, it also changes to "_events" (because "_events" IS "newData"). This can lead to dangerous side effects if they are not intended.

In the second case, subsequent changes to 'newData' are not reflected as changes to '_events', because '_events' is a copy of the new data. Correctly it depends on the semantics of your application. The same applies, on the contrary, if you have a "get" matching this "set."

If you are only going to update the contents of "_events" and not modify what it refers to, you should also consider making it final.

Hmmm. I just noticed that "_data" is mentioned only once in your example. I assumed that "_data" and "_events" are the same thing (i.e., this is a typo) - otherwise why would you mention "_data" at all?

0
source

The main differences:

List implementation:
The List passed cannot be an ArrayList , it can be (for example) a LinkedList . Just using the list that went through can seriously affect the performance of your application if you directly access the elements of your list through your index; ArrayList.get(i) is O (1), but LinkedList.get(i) is O (n).

Data Integrity:
If you simply use the list provided to you, the caller can save a link to it and (much) change the list later without knowing its class. This can lead to unpredictable behavior in your application. For example, you can store information about the contents of a list, which would then be invalid in the list, would be changed without your knowledge of the class, which would lead to inconsistent data. Similarly, your class can change the list and the client will not (usually) know, so the opposite may be true - the client may have data inconsistencies.

Memory leak: A link to a list can be stored by both the caller and your class. This can cause the list to not be garbage collected if expected, either.

For these reasons (and perhaps more), the best practice is usually to copy a list that was accepted if there is no good reason for this, and the fact that you are not making a copy is well documented so that everyone knows what the consequences are.

0
source

Source: https://habr.com/ru/post/947838/


All Articles