一、 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. LintCode刷题笔记--Longest Increasing Subsequence

    标签: 动态规划 描述: Given a sequence of integers, find the longest increasing subsequence (LIS). You code s ...

  2. Codeforces Round #263 (Div. 2) A. Appleman and Easy Task【地图型搜索/判断一个点四周‘o’的个数的奇偶】

    A. Appleman and Easy Task time limit per test 1 second memory limit per test 256 megabytes input sta ...

  3. Django1.11使用命令makemigrations提示No Changes

    在项目中,遇到models模型变动,变动后合并发生问题,故当时做了删除应用文件夹下migrations文件,由于数据库里无较多新数据,故删除后重建,但重建后执行模型合并操作结果为No Changes, ...

  4. linux包之包管理rpm-yum

    背景 YUM(Yellow dog Updater, Modified)为多个Linux发行版的前端软件包管理器,例如 Redhat RHEL, CentOS & Fedora. YUM通过调 ...

  5. 【JZOJ4876】【NOIP2016提高A组集训第10场11.8】基因突变

    题目描述 邪恶的707刚刚从白垩纪穿越回来,心中产生了一个念头:我要统治人类! 但是统治人类是很庞大且复杂的一个工程,707尝试了洗脑,催眠,以及武装镇压都没能成功地统治人类,于是她决定从科学上对人类 ...

  6. 【JZOJ4869】【NOIP2016提高A组集训第9场11.7】平均数

    题目描述 数据范围 解法 二分答案. 对于一个答案mid,要求出区间平均数小于mid的个数ans. 给所有数减去mid,那么问题转化为求出所有区间和为负数的个数. 对于一个区间[l,r],如果sum[ ...

  7. 在哈尔滨的寒风中EOJ 3461【组合数学】

    http://acm.ecnu.edu.cn/problem/3461/ 还是能力不够,不能看出来棋盘足够大时,马是可以到达任何位置的.还是直接看题解怎么说的吧:(http://acm.ecnu.ed ...

  8. SqlSugar 笔记

    分组: 日期分组一: var result = await temp .GroupBy("date_format(Day,'%Y-%m')") .Select(s => ne ...

  9. oracle表内连接和外连接

    n  概述 表连接分为内连接和外连接 n  内连接 内连接实际上就是利用where子句对两张表形成的笛卡尔集进行筛选,我们前面学习的查询都是内连接,也是在开发过程中用的最多的连接查询. 基本语法: s ...

  10. 【NS2】使用SourceInsight阅读NS源代码全攻略(转载)

    NS的源码底层是C++,采用了C++/Tcl分裂对象模型,架构完善,堪称OOP编程的典范.但是NS源码体系庞大,源文件有2千多个,阅读起来不是特别方便,我推荐使用SourceInsight3.5.具体 ...