Item5:消除过期对象的引用

  JVM为我们实现了GC(垃圾回收)的功能,让我们从手工管理内存中解放了出来,这固然很好,但并不意味着我们就再也不需要去考虑内存管理的事情了;我们用简单的栈实现的例子来解释:

public class Stack {
private Object[] elements;
private in size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack(){
elements = new Object[DEFAULT_INITIAL_CAPACITY];
} public void push(Object e){
ensureCapacity();
elements[size++] = e;
} public Object pop(){
if(size == 0){
return new EmptyStackException();
}
return element[--size];
} //保证每当栈满就会自动扩容为原来的两倍
private void ensureCapacity(){
if(elements.length == size){
elements = Arrays.copyOf(elements, 2*size+1);
}
}
}

这段程序没有什么明显的错误,无论怎么测试,结果似乎都是正确的,但不严格的讲,这段程序存在"内存泄漏"的风险,极端情况下,会导致磁盘交换(Disk Paging),甚至是程序失败(OutOfMemoryError);

为什么是内存泄漏?书中给出的解释是:从栈中pop出来的对象的引用还被栈内部维护着,这些引用被称作"过期引用"(指下标小于size的那些元素的引用),所以,GC不会去处理该对象以及该对象所引用的其他对象,内存就被这样渐渐"填满"导致溢出.

修复方法,改写pop()

public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
Object result = element[--size];
elements[size] = null;    //清空出栈对象的引用,告知GC可以释放其资源
return result;
}

手动将过期引用告知垃圾回收器还有的好处就是,如果之后又用了此过期引用,程序就会报空指针异常,而不是一直"错误下去"..

内存泄漏的另一常见来源是缓存,对象引用在缓存中就很容易被忘记,如果不用它会长时间驻留缓存.对应的几种解决方法:

  1.使用WeakHashMap代表缓存,该类拥有expungeStaleEntries方法,用于清除那些外部没有引用并且缓存内存在的键,来段代码说明:

public class Test {
public static void main(String[] args) throws Exception {
String a = new String("a");
String b = new String("b");
Map weakmap = new WeakHashMap();
Map map = new HashMap();
map.put(a, "aaa");
map.put(b, "bbb"); weakmap.put(a, "aaa");
weakmap.put(b, "bbb"); map.remove(a); a=null;
b=null; System.gc(); } }

  由于HashMap移除了a的引用,且清除了a的外部引用,此时a的引用只有WeakHashMap来维护了,此时WeakHashMap会自动舍弃掉a,但HashMap还保存着b的引用,所以b不会被WeakHashMap丢弃掉。在工程当中WeakHashMap是很实用的,我们使用短时间内就过期的缓存时最好使用weakHashMap。

  2.可以将清除过期引用的任务交给“Time”或“ScheduledThreadPoolExecutor”来完成

  即定时清除过期引用。

  

  3.使用LinkedHashMap当做缓存,调用removeEldesttEntry方法清除过期引用

  

  4.直接使用java.lang.ref

  说道ref包,就绕不开Java的四类引用:强引用,软引用,弱引用,虚引用。这里大致概括一下,具体引用就不过多赘述,细节可以参照深入探讨java.lang.ref包

    强引用:只要引用存在,垃圾回收器永远不会回收,Object obj = new Object()的形式

    软引用:非必须引用,内存溢出之前进行回收,可以通过以下代码实现,SoftReference<Object> sf = new SoftReference<Object>(obj)的形式,通过sf.get()获取对象,软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。

    弱引用:第二次垃圾回收时回收,WeakReference<Object> wf = new WeakReference<Object>(obj)的形式,弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。

    虚引用:垃圾回收时回收,无法通过引用取到对象值,PhantomReference<Object> pf = new PhantomReference<Object>(obj)的形式,pf.isEnQueued()主要用于检测对象是否已经从内存中删除。

  

关于内存泄漏的检测,往往不会表现的很明显,但它能在系统中存在很多年,只有通过检查代码或借助于Heap剖析工具(Heap Profiler)发现问题,关于Heap Profiler我有机会在单独介绍。

Item6:避免使用终结方法(finalizer)

下面由一段代码引入:

/**
* @author YHW
* @ClassName: Test1
* @Description:
* @date 2019/1/4 20:55
*/
public class Test1 { public static void main(String[] args){
Bob bob = new Bob();
System.out.println(bob.getState());
Thread thread = new Thread(){
@Override
public void run() {
super.run();
try{
sleep(2000);
}catch(Exception e){
e.printStackTrace();
}finally{
bob.setClosed(true);
} }
};
thread.start();
System.out.println(bob.getState());
} }

运行结果截图:

在main方法中开了一个子线程,我故意睡了2秒,故根本走不到终结方法那里,主程序就”关闭“了,这时候子线程还没执行完,这有可能因此而产生终结对象的速度达不到对象入队的速度,出现内存泄漏而死掉,所以我们不应该以来终结方法来更新重要的持久状态,而且并没有很轻便的方法能够避免这样的问题;

由此引出了终结方法所具备的特性:

  1.finalizer方法的线程优先级比当前程序的其他线程优先级要低,且JAVA语言规范不保证任何线程中finalizer方法的执行;

  2.及时执行终结方法是JVM的一大功能,但在不同的JVM实现都大相径庭,有时候终结方法的线程优先级会非常低,造成JVM“没时间”释放不用的资源,引起OutOfMemoryError;

  3.唯一声称保证终结方法执行的System.runFinalizersOnExit和Runtime.runFinalizersOnExit都存在致命缺陷,已经废弃了;

  4.finalizer会有非常严重的性能损失;

提升Java代码质量(二)的更多相关文章

  1. 提升Java代码质量(三)

    Item7:覆盖equals时需要遵守通用约定 在我们日常开发过程中,重写equals是比较常用的,但存在许多不合适的覆盖方式导致错误,最好的避免方法就是不去重写equals.但有时我们的业务又需要建 ...

  2. 提升Java代码质量(一)

    博主双12入手了一本"Effective Java第二版",本系列文章将初步梳理书中内容,我也查了些资料,我会针对知识点做一点展开,方便以后复习回顾; Item1.考虑用静态工厂代 ...

  3. 拔高你的Java代码质量吧:推荐使用枚举定义常量(转)

    提高你的Java代码质量吧:推荐使用枚举定义常量 一.分析 常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量.不过,在1.5版之后有了改进,即新增了一 ...

  4. 提高Java代码质量的Eclipse插件之Checkstyle的使用详解

    提高Java代码质量的Eclipse插件之Checkstyle的使用详解 CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具.它能够自动化代 ...

  5. java代码解析二维码

    java代码解析二维码一般步骤 本文采用的是google的zxing技术进行解析二维码技术,解析二维码的一般步骤如下: 一.下载zxing-core的jar包: 二.创建一个BufferedImage ...

  6. 提高Java代码质量的Eclipse插件之Checkstyle的使用具体解释

    CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发者遵守某些编码规范的工具.它可以自己主动化代码规范检查过程.从而使得开发者从这项重要可是枯燥的任务中解脱出来. Ch ...

  7. java 性能优化:35 个小细节,让你提升 java 代码的运行效率

    前言 代码 优化 ,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没 ...

  8. JAVA性能优化:35个小细节让你提升java代码的运行效率

    代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是, ...

  9. Java代码质量度量工具大阅兵

    FindBugs FindBugs, a program which uses static analysis to look for bugs in Java code. It is free so ...

随机推荐

  1. 洛谷 P4512 [模板] 多项式除法

    题目:https://www.luogu.org/problemnew/show/P4512 看博客:https://www.cnblogs.com/owenyu/p/6724611.html htt ...

  2. Docker入门(二):安装/卸载

    这个<Docker入门系列>文档,是根据Docker官网(https://docs.docker.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指 ...

  3. 选择排序(java)

    选择排序的思想是:内外两层循环,第一层循环从第一个数开始到倒数第一个数, 第二层循环从上一层的数开始, 与上一层循环的数比较,如果小于则交换位置. 代码如下: public class SelectS ...

  4. 关于java中equals与==的区别的小实验

    java中equals与==经常容易混淆,简单一点说就是equals比较的是值是否相等,是一种方法,==比较的两个对象在JVM中的地址,是一种操作符. 做了几个小实验比较结果. 实验一: String ...

  5. [xdoj1227]Godv的数列(crt+lucas)

    解题关键:1001=7*11*13,模数非常小,直接暴力lucas.递归次数几乎为很小的常数.最后用中国剩余定理组合一下即可. 模数很小时,一定记住lucas定理的作用 http://acm.xidi ...

  6. Http协议-概要

    Http协议(超文本传输协议)是位于TCP/IP结构中的应用层的一种传输协议,规定了万维网服务器之间相互通信的规则.比如比较常见的Web浏览器客户端与应用服务器的通信!万维网服务器之间互相通信的时候往 ...

  7. JAVA正则表达式之 Pattern介绍

    1.简介: java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包. 它包括两个类:Pattern和Matcher. Pattern 一个Pattern是一个正则表 ...

  8. 在windows10环境下给PHPStorm配置xdebug断点调试功能

    笔者的开发环境: wampserver2.5系统环境包 操作系统:windows10 64位专业版. php版本:php5.512 Apache版本:2.49 好了下面介绍,phpstorm配置xde ...

  9. 集成Python Shell

    每次启动shell会话都要导入Python相关对象(数据库实例和模型),这是件十分枯燥的工作.为了避免一直重复导入,我们可以做些配置,让flask-script的shell命令自动导入特定的对象. F ...

  10. 洛谷P1578 奶牛浴场

    P1578 奶牛浴场 题目描述 由于John建造了牛场围栏,激起了奶牛的愤怒,奶牛的产奶量急剧减少.为了讨好奶牛,John决定在牛场中建造一个大型浴场.但是John的奶牛有一个奇怪的习惯,每头奶牛都必 ...