深入java面向对象五:Java的内存管理
一、 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的内存管理的更多相关文章
- 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封装 ...
- 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封装 ...
- # 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封装 ...
- 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封装 ...
- 081 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 06 new关键字
081 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 06 new关键字 本文知识点:new关键字 说明:因为时间紧张,本人写博客过程中只是 ...
- 078 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 03 创建类
078 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 03 创建类 本文知识点:创建类 说明:因为时间紧张,本人写博客过程中只是对知识点的关 ...
- 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封装 ...
- 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封装 ...
- 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封装 ...
- 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现
088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现 本文知识点:Java封装的代码实现 说明:因为时间紧张,本人写博客过程中只 ...
随机推荐
- python中数字转换成字符串
数字转换成字符串: num=123 str='%d' %num str就变成了"123"
- Katalon系列二十:读写Excle
import org.apache.poi.xssf.usermodel.XSSFSheet import org.apache.poi.xssf.usermodel.XSSFWorkbook Fil ...
- linux系统 (实验二)实验楼的课程笔记
who am i 打印用户名和终端 终端的启动时间 whoami 打印用户名 who 命令其它常用参数 参数 说明 -a 打印能打印的全部 -d 打印死掉的进程 -m 同am i,mom li ...
- js流星雨效果
css部分 div { border: 0px solid #fff; border-width: 0px 90px 2px 90px; border-color: transparent trans ...
- Linux常用命令3 文件搜索命令
文件搜索非常占用资源,所以尽量不要使用这个命令 避免少用该命令最好的方式是设置好文件夹结构,文件不要乱放 1.文件搜索命令:find 命令名称:find 所在路径:/bin/find 执行权限:所有用 ...
- JS运算的优先级
汇总表 下面的表将所有运算符按照优先级的不同从高到低排列. 优先级 运算类型 关联性 运算符 20 圆括号 n/a ( … ) 19 成员访问 从左到右 … . … 需计算的成员访问 从左到右 … [ ...
- jq处理JSON数据, jq Manual (development version)
jq 允许你直接在命令行下对 JSON 进行操作,包括分片.过滤.转换等等.让我们通过几个例子来说明 jq 的功能:一.输出格式化,漂亮的打印效果如果我们用文本编辑器打开 JSON,有时候可能看起来会 ...
- viewpager实现进入程序之前的欢迎界面效果
用viewpager实现该效果大致需要5步 1,用support.v4包下的ViewPager.xml布局如下: <android.support.v4.view.ViewPager andro ...
- DAY1-作业
Python-day1-------> 本节内容: Python介绍 发展史 Python 2 or 3? 安装 Hello World程序 变量 用户输入 模块初识 .pyc是个什么鬼? 数据 ...
- codevs1506 传话
题目描述 Description 一个朋友网络,如果a认识b,那么如果a第一次收到某个消息,那么会把这个消息传给b,以及所有a认识的人. 如果a认识b,b不一定认识a. 所有人从1到n编号,给出所有“ ...