一、 Java对象的引用种类

Java内存管理包括内存分配和内存回收, 这个动作都是由JVM自动完成,所以过多的内存分配增加了内存的消耗,且垃圾回收线程的不断运行会给后台增加压力,降低系统的性能。

1.1  对象在内存中的状态

· 可达状态: 当一个对对象被创建后,有一个以上的引用变量引用它,在它处于可达状态。

·可恢复状态: 如果程序中的某个对象不再有任何引用变量引用它,它将先进入可恢复状态。

· 不可达状态: 当对象的所有关联都被切断,且系统调用所有对象的finalize方法依然没有使该对象变成可达状态,它就将永远失去引用,等待被回收。

1.2 强引用

java程序创建一个对象,并把这个独享赋值给一个引用变量,这个引用变量就是强引用。

JVM是肯定不会回收强引用所引用的Java对象。

1.3 软引用

软引用需要通过SoftReference实现,对于只有软引用的对象而言,当系统的内存空间足够时,它不会被系统回收,程序也可以使用该对象;当系统的内存空间充足时,系统不会回收它。 当系统的内存空间不足时,系统将会回收它。

当程序需要大量创建某个类的新对象时,而且有可能重新访问已创建老对象时,可以充分使用软引用来解决内存紧张的问题。

class Person
{
String name;
int age;
public Person(String name , int age)
{
this.name = name;
this.age = age;
}
public String toString()
{
return "Person[name=" + name
+ ", age=" + age + "]";
}
}
public class SoftReferenceTest
{
public static void main(String[] args)
throws Exception
{
SoftReference<Person>[] people =
new SoftReference[100000];
for (int i = 0 ; i < people.length ; i++)
{
people[i] = new SoftReference<Person>(new Person(
"名字" + i , (i + 1) * 4 % 100));
}
System.out.println(people[2].get());
System.out.println(people[4].get());
//通知系统进行垃圾回收
System.gc();
System.runFinalization();
//垃圾回收机制运行之后,SoftReference数组里的元素保持不变
System.out.println(people[2].get());
System.out.println(people[4].get());
}
}

上面程序创建了一个长度为100的SoftReference数组,程序使用这个数组来保存100个person对象,当系统内存足够时,即使系统进行垃圾回收,垃圾回收机制也不会回收这些Person对象所占的内存空间。

1.4 弱引用

弱引用与软引用有点相似,区别在于弱引用所引用对象的生存空间更短。 对于只有弱引用的对象而言,当系统的垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占内存。

public class WeakReferenceTest
{
public static void main(String[] args) throws Exception
{
//创建一个字符串对象
String str = new String("疯狂Java讲义");
//创建一个弱引用,让此弱引用引用到"疯狂Java讲义"字符串
WeakReference<String> wr = new WeakReference<String>(str); //①
//切断str引用和"疯狂Java讲义"字符串之间的引用
str = null; //②
//取出弱引用所引用的对象
System.out.println(wr.get()); //③
//强制垃圾回收
System.gc();
System.runFinalization();
//再次取出弱引用所引用的对象
System.out.println(wr.get()); //④
}
}

系统输出:

疯狂Java讲义

null

从上图可以看出: 此时的“疯狂Java讲义”字符串对象只有一个弱引用对象引用它,程序依然可以通过这个弱引用对象来访问该字符串常量; 但是,当启动垃圾回收机制,只有弱引用的对象就会被清理掉,系统在访问弱引用的空间,就会发现以为null,表明该对象已经被清理掉了。

与WeakReference功能类似的还有WeakHashMap,用于保存对个需要使用弱引用来引用的对象。

class CrazyKey
{
String name;
public CrazyKey(String name)
{
this.name = name;
}
//重写hashCode()方法
public int hashCode()
{
return name.hashCode();
}
//重写equals方法
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (obj != null && obj.getClass() == CrazyKey.class)
{
return name.equals(((CrazyKey)obj).name);
}
return false;
}
//重写toString()方法
public String toString()
{
return "CrazyKey[name=" + name + "]";
}
}
public class WeakHashMapTest
{
public static void main(String[] args) throws Exception
{
WeakHashMap<CrazyKey , String> map
= new WeakHashMap<CrazyKey , String>();
//循环放入10个key-value对
for (int i = 0 ; i < 10 ; i++)
{
map.put(new CrazyKey(i + 1 + "") , "value" + (i + 11));
}
//垃圾回收之前,WeakHashMap与普通HashMap并无区别
System.out.println(map);
System.out.println(map.get(new CrazyKey("2")));
//通知垃圾回收
System.gc();
//暂停当前线程50ms,让垃圾回收后台线程获得执行
Thread.sleep(50);
//垃圾回收后,WeakHashMap里所有Entry全部清空
System.out.println(map);
System.out.println(map.get(new CrazyKey("2")));
}
}

可以看出,在垃圾回收机制前,WeakHashMap的功能与普通的HashMap并没有太大的区别,它们的功能完全相似。 而一旦垃圾回收机制被执行,WeakHashMap中的所有key-value都会被清空。

1.5 虚引用

虚引用不能单独使用,它的主要作用是跟踪对象被垃圾回收的状态,程序可以通过检查与虚引用关联的引用队列中是否包含指定的虚引用,从而了解虚引用所引用对象是否即将被回收。

二、 内存泄露

内存泄漏是指: 程序运行过程中不断的分配内存,那些不再使用的内存空间应该及时回收它们,从而保证系统可以再次使用这些内存,如果存在无用的内存没有回收回来,这就是内存泄露。

三、 内存管理技巧

1. 尽量使用直接量

2. 使用StringBuffer、StringBuilder进行字符串连接

3. 尽早释放无用对象  obj=null

4. 尽量少用静态变量

5. 避免在经常调用的方法、循环中创建java对象

for(int i=0;i<100;i++){
Object obj = new Object(); // 避免使用
}

6. 缓存经常使用的对象

7. 尽量不要使用finalize方法

8. 考虑使用SoftReferenct引用

注: 文章内容来自《疯狂Java:突破程序员基本功的16课》, 作者: 李刚

深入java面向对象五:Java的内存管理的更多相关文章

  1. 090 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 04 使用包进行类管理(2)——导入包

    090 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  2. 089 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 使用包进行类管理(1)——创建包

    089 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  3. # 095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 03 封装总结 01 封装知识点总结

    095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  4. 091 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 01 static关键字(上)

    091 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  5. 081 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 06 new关键字

    081 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 06 new关键字 本文知识点:new关键字 说明:因为时间紧张,本人写博客过程中只是 ...

  6. 078 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 03 创建类

    078 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 03 创建类 本文知识点:创建类 说明:因为时间紧张,本人写博客过程中只是对知识点的关 ...

  7. 094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 04 static关键字(续)

    094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  8. 093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 03 static关键字(下)

    093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  9. 092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 02 static关键字(中)

    092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  10. 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现

    088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现 本文知识点:Java封装的代码实现 说明:因为时间紧张,本人写博客过程中只 ...

随机推荐

  1. JavaScript字符串、数组、对象方法总结

    字符串方法 示例字符串: const str = "hello,kitty,hello,vue "; 一.基本方法 charAt(n) 返回指定索引的字符 charCodeAt(n ...

  2. HTTP请求封装Java工具类

    装载自:http://www.open-open.com/lib/view/open1384844838743.html package com.wiker; import java.io.Buffe ...

  3. PHP核心编程--文件上传(包含多文件上传)

    一.单文件上传 图片上传界面: <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  4. RNN与 LSTM 网络

    循环神经网络(RNN) 人们的每次思考并不都是从零开始的.比如说你在阅读这篇文章时,你基于对前面的文字的理解来理解你目前阅读到的文字,而不是每读到一个文字时,都抛弃掉前面的思考,从头开始.你的记忆是有 ...

  5. 【C++】位运算实现加减乘除

    #include<iostream> #include<assert.h> using namespace std; // 位运算实现加减乘除 int myAdd(int nu ...

  6. GitHub Top 100 Objective-C 项目简介

    主要对当前 GitHub 排名前 100 的项目做一个简单的简介, 方便初学者快速了解到当前 Objective-C 在 GitHub 的情况. 若有任何疑问可通过微博@李锦发联系我 GitHub 地 ...

  7. MUI - 解决动态列表页图片懒加载再次加载不成功的bug

    首先描述一下功能 实现列表页动态加载 通过官方提供的"下拉刷新和上拉刷新"及"图片懒加载"示例实现. http://www.cnblogs.com/philly ...

  8. postman post 数据格式

    postman post 数据的时候,选择raw的tab ,选择json. 然后在下面的提交json数据, {"photoPath":"bbbbbbbbbbbbbb&qu ...

  9. 『创造 Cloud Toolkit』贡献排行榜——如何参与定义一款 IDE 插件?

    自从我们团队在去年12月发布 Cloud Toolkit(一款让开发部署效率提速 8 倍的 IDE 插件)以来,已帮助数以万计的开发者们提高了云上的部署效率,期间,开发者们不仅积极地向 Cloud T ...

  10. @codeforces - 1209G2@ Into Blocks (hard version)

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 定义一个序列是好的,当且仅当这个序列中,相等的两个数之间的所有数 ...