How Java effectively avoids oom: good at using soft and weak references
Presumably many friends will not be unfamiliar with the error of Oom (OutOfMemory), and when encountering this kind of mistake how to solve this problem effectively? Today, let's take a look at how to use soft and weak references to effectively solve the oom problem in your program. The following is the directory outline for this article:
I. Understanding the concept of strong references, soft references, weak references, and virtual references
Two. Further understanding of soft and weak references
Three. How to solve oom problems with soft and weak references
If there are any mistakes, I would appreciate your understanding and criticism.
Please respect the author's labor results, reproduced please indicate the original link:
Http://www.cnblogs.com/dolphin0520/p/3784171.html
I. Understanding the concept of strong references, soft references, weak references, and virtual references
In Java, although it is not necessary for programmers to manually manage the life cycle of objects, it is necessary to use soft and weak references if you want certain objects to have a certain life cycle (for example, the JVM will automatically reclaim some objects to avoid outofmemory errors when memory is low).
Starting with Java SE2, there are four types of references: Strong references, soft references, weak references, and virtual references. These four reference types are available in Java for two purposes: the first is to allow programmers to determine the life cycle of certain objects through code, and the second is to facilitate garbage collection by the JVM. Here's a look at the concepts of these four types of references:
1. Strong references (strongreference)
Strong references are commonly found in program code, such as the following code in which both object and Str are strong references:
12 |
Object object = new Object(); String str = "hello" ; |
As long as an object has a strong reference associated with it, the JVM must not reclaim the object, even if the JVM prefers to throw a outofmemory error in case of low memory. For example, the following code:
12345678910 |
public
class
Main {
public
static void
main(String[] args) {
new
Main().fun1();
}
public
void
fun1() {
Object object =
new
Object();
Object[] objArr =
new
Object[
1000
];
}
}
|
When running to object[] Objarr = new object[1000]; when there is not enough memory, the JVM throws an oom error and does not reclaim the object pointed to by object. Note, however, that when Fun1 runs out, both object and Objarr are no longer present, so the objects they point to will be reclaimed by the JVM.
If you want to break the association between a strong reference and an object, you can display the reference assignment to NULL, so that the JVM reclaims the object at the appropriate time.
For example, in the clear method of the vector class, the cleanup is done by assigning a reference to null:
/** * Removes the element at the specified position in this Vector. * Shifts Any subsequent elements to the left (subtracts one from their * indices). Returns the element that is removed from the Vector. * * @throws arrayindexoutofboundsexception If the index is out of range * ({@code Index < 0 | | Index >= Size ()}) * @param the index of the element to be removed * @return element, was removed * @since 1. 2 * /Public synchronized E Remove (int index) { modcount++; if (index >= elementcount) throw new ArrayIndexOutOfBoundsException (index); Object oldValue = Elementdata[index]; int nummoved = elementcount-index-1; if (nummoved > 0) system.arraycopy (Elementdata, index+1, Elementdata, index, nummoved); Elementdata[--elementcount] = null; Let GC does its work return (E) oldValue; }
/** * Removes the element at the specified position in this Vector. * Shifts Any subsequent elements to the left (subtracts one from their * indices). Returns the element that is removed from the Vector. * * @throws arrayindexoutofboundsexception If the index is out of range * ({@code Index < 0 | | Index >= Size ()}) * @param the index of the element to be removed * @return element, was removed * @since 1. 2 * /Public synchronized E Remove (int index) { modcount++; if (index >= elementcount) throw new ArrayIndexOutOfBoundsException (index); Object oldValue = Elementdata[index]; int nummoved = elementcount-index-1; if (nummoved > 0) system.arraycopy (Elementdata, index+1, Elementdata, index, nummoved); Elementdata[--elementcount] = null; Let GC does its work return (E) oldValue; }
2. Soft Reference (SoftReference)
Soft references are used to describe some useful but not necessary objects, which are represented in Java by the Java.lang.ref.SoftReference class. For objects associated with soft references, the JVM reclaims the object only when there is insufficient memory. Therefore, this is a good way to solve the problem of oom, and this feature is well suited for caching: such as Web caching, image caching, and so on.
A soft reference can be used in conjunction with a reference queue (Referencequeue), and if the object referenced by the soft reference is reclaimed by the JVM, the soft reference is added to the reference queue associated with it. The following is an example of use:
123456789 |
import
java.lang.ref.SoftReference;
public
class
Main {
public
static
void main(String[] args) {
SoftReference<String> sr =
new
SoftReference<String>(
new
String(
"hello"
));
System.out.println(sr.get());
}
}
|
3. Weak references (WeakReference)
Weak references are also used to describe non-essential objects, and when the JVM is garbage collected, the objects associated with the weak references are reclaimed regardless of the adequacy of the memory. In Java, it is represented by the Java.lang.ref.WeakReference class. The following are examples of use:
123456789101112 |
import
java.lang.ref.WeakReference;
public
class
Main {
public
static
void main(String[] args) {
WeakReference<String> sr =
new
WeakReference<String>(
new
String(
"hello"
));
System.out.println(sr.get());
System.gc();
//通知JVM的gc进行垃圾回收
System.out.println(sr.get());
}
}
|
The output is:
Hellonull
Hellonull
The second output is null, which means that the objects associated with the weak reference must be reclaimed as long as the JVM is garbage collected. It is important to note, however, that the object referred to by the weak reference is associated with only a weak reference, and if there is a strong reference associated with it, the object will not be reclaimed when it is garbage collected (as is the case with soft references).
A weak reference can be used in conjunction with a reference queue (Referencequeue), and if the object referenced by the weak reference is reclaimed by the JVM, the soft reference is added to the reference queue associated with it.
4. Virtual references (phantomreference)
A virtual reference differs from the previous soft reference and weak reference, and it does not affect the life cycle of the object. Represented in Java with the Java.lang.ref.PhantomReference class. If an object is associated with a virtual reference, it can be reclaimed by the garbage collector at any time, as with no reference to it.
Note that a virtual reference must be used in association with a reference queue, and when the garbage collector is ready to reclaim an object, if it finds a virtual reference, it adds the virtual reference to the reference queue associated with it. The program can see if the referenced object is going to be garbage collected by judging whether the reference queue has been added to the virtual reference. If the program discovers that a virtual reference has been added to the reference queue, it can take the necessary action before the memory of the referenced object is reclaimed.
1234567891011 |
import
java.lang.ref.PhantomReference;
import
java.lang.ref.ReferenceQueue;
public
class
Main {
public
static
void
main(String[] args) {
ReferenceQueue<String> queue =
new
ReferenceQueue<String>();
PhantomReference<String> pr =
new PhantomReference<String>(
new
String(
"hello"
), queue);
System.out.println(pr.get());
}
}
|
Two. Further understanding of soft and weak references
For strong references, we usually use them when writing code. And for the other three types of references, the most used is soft and weak references, these 2 kinds of similarities and differences. They are all used to describe non-essential objects, but objects associated with soft references are recycled only when they are out of memory, and objects associated with weak references are always recycled when the JVM is garbage collected.
In the SoftReference class, there are three methods, two construction methods, and a Get method (similar to wekreference):
Two methods of construction:
123456789 |
public
SoftReference(T referent) {
super
(referent);
this
.timestamp = clock;
}
public
SoftReference(T referent, ReferenceQueue<?
super
T> q) {
super
(referent, q);
this
.timestamp = clock;
}
|
The Get method is used to obtain a reference to the object associated with the soft reference, and returns null if the object is recycled.
When using soft references and weak references, we can display the System.GC () to notify the JVM of garbage collection, but note that, although a notification is issued, the JVM does not necessarily execute immediately, which means that the JVM is not guaranteed to be garbage collected at this time.
Three. How to solve oom problems with soft and weak references
The basics of soft and weak references are described earlier, so how can you use them to optimize program performance to avoid oom problems?
As an example, if there is an application that needs to read a large number of local images, it can seriously affect performance if the images are read from the hard disk every time, but if they are all loaded into memory and can cause memory overflow, a soft reference is used to solve the problem.
The design idea is: With a hashmap to save the path of the picture and the corresponding picture object associated with the mapping between the soft reference, when the memory is low, the JVM will automatically reclaim the space occupied by these cached picture objects, thus effectively avoiding the problem of oom. It is often used in Android development for a large number of image downloads.
The following code is excerpted from the blog:
http://blog.csdn.net/arui319/article/details/8489451
12345678910111213141516171819202122232425262728293031323334353637383940 |
.....
private
Map<String, SoftReference<Bitmap>> imageCache =
new
HashMap<String, SoftReference<Bitmap>>();
<br>....
public
void addBitmapToCache(String path) {
// 强引用的Bitmap对象
Bitmap bitmap = BitmapFactory.decodeFile(path);
// 软引用的Bitmap对象
SoftReference<Bitmap> softBitmap =
new
SoftReference<Bitmap>(bitmap);
// 添加该对象到Map中使其缓存
imageCache.put(path, softBitmap);
}
public
Bitmap getBitmapByPath(String path) {
// 从缓存中取软引用的Bitmap对象
SoftReference<Bitmap> softBitmap = imageCache.get(path);
// 判断是否存在软引用
if
(softBitmap ==
null
) {
return
null
;
}
// 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
Bitmap bitmap = softBitmap.get();
return
bitmap;
}
|
Of course, here we give the cache substitution policy to the JVM to execute, this is a relatively simple processing method. A bit more complex cache, we can design a separate class, where the problem is related to the cache policy, the specific can refer to a previous blog post: "Cache algorithm (page replacement algorithm)-fifo, LFU, LRU"
Resources:
"In-depth understanding of JVM virtual machines"
http://blog.csdn.net/arui319/article/details/8489451
http://blog.csdn.net/zsuguangh/article/details/6429592
Http://mobile.51cto.com/abased-406998.htm
How Java effectively avoids oom: good at using soft and weak references