深入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封装的代码实现 说明:因为时间紧张,本人写博客过程中只 ...
随机推荐
- Codeforces 451D
题目链接 D. Count Good Substrings time limit per test 2 seconds memory limit per test 256 megabytes inpu ...
- python ndarray相关操作:拼接
- 【水滴石穿】react-native-video-project
感觉这个是很有才华的博主,毕竟是可以在npm 包里面留后门的程序员 博主的gihtub关于这个项目的地址是:https://github.com/ikimiler/react-native-video ...
- 阿里云ecs环境配置
在阿里云 CentOS 服务器(ECS)上搭建 nginx + mysql + php-fpm 环境 https://ninghao.net/blog/1368 阿里云ecs从购买到环境搭建和建站!! ...
- qt 鼠标拖动窗口放大缩小
// 鼠标拖动 具体实现void mouseMoveEvent(QMouseEvent * pEvent) { if (pEvent->buttons() & Qt::LeftButto ...
- CSS3--关于z-index不生效问题
最近写CSS3和js结合,遇到了很多次z-index不生效的情况: 1.在用z-index的时候,该元素没有定位(static定位除外) 2.在有定位的情况下,该元素的z-index没有生效,是因为该 ...
- 一键制作启动elasticsearch和kibana启动的脚本可执行程序
1.测试环境 测试环境: . windows10专业版 . elasticsearch6.5.4 . kibana6.5.4 2.启动的脚本run.py import os import time i ...
- python 使用自定义的类方法
- C++异常相关
使用异常处理,程序中独立开发的各部分能够就程序执行期间出现的问题相互通信,并处理这些问题.C++ 的异常处理中,需要由问题检测部分抛出一个对象给处理代码,通过这个对象的类型和内容,两个部分能够就出现了 ...
- 亚洲唯一,阿里云SLB位列Gartner全球网络负载均衡市场前五
近日,Gartner发布了最新的全球企业级网络设备市场份额报告“Market Share: Enterprise Network Equipment by Market Segment, Worldw ...