当你从c&c++转到一门具有垃圾回收功能的语言时,程序员的工作就会变得更加容易,因为你用完对象,他们会被自动回收,但是,java程序员真的不需要考虑内存泄露吗? 其实不然

1.举个例子-看你能否找出内存泄漏

  1. import java.util.Arrays;
  2. public class Stack {
  3. private Object[] elements;
  4. private int size = 0;
  5. private static final int DEFAULT_INITIAL_CAPACITY = 16;
  6. public Stack() {
  7. elements = new Object[DEFAULT_INITIAL_CAPACITY];
  8. }
  9. public void push(Object e) {
  10. ensureCapacity();
  11. elements[size++] = e;
  12. }
  13. public Object pop() {
  14. if (size == 0)
  15. throw new EmptyStackException();
  16. return elements[--size];
  17. }
  18. private void ensureCapacity() {
  19. if (elements.length == size)
  20. elements = Arrays.copyOf(elements, 2 * size + 1);
  21. }
  22. }

1.1原因分析

上述程序并没有明显的错误,但是这段程序有一个内存泄漏,随着GC活动的增加,或者内存占用的不断增加,程序性能的降低就会表现出来,严重时可导致内存泄漏,但是这种失败情况相对较少。

代码的主要问题在pop函数,下面通过这张图示展现

假设这个栈一直增长,增长后如下图所示



当进行大量的pop操作时,由于引用未进行置空,gc是不会释放的,如下图所示

从上图中看以看出,如果栈先增长,在收缩,那么从栈中弹出的对象将不会被当作垃圾回收,即使程序不再使用栈中的这些队象,他们也不会回收,因为栈中仍然保存这对象的引用,俗称过期引用,这个内存泄露很隐蔽。

1.2解决方法

  1. public Object pop() {
  2. if (size == 0)
  3. throw new EmptyStackException();
  4. Object result = elements[--size];
  5. elements[size] = null;
  6. return result;
  7. }

一旦引用过期,清空这些引用,将引用置空。

2.缓存泄漏

内存泄漏的另一个常见来源是缓存,一旦你把对象引用放入到缓存中,他就很容易遗忘,对于这个问题,可以使用WeakHashMap代表缓存,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值

2.1代码示例

  1. /**
  2. * Created by liuroy on 2017/2/25.
  3. */
  4. import java.util.HashMap;
  5. import java.util.Map;
  6. import java.util.WeakHashMap;
  7. import java.util.concurrent.TimeUnit;
  8. public class Test {
  9. static Map wMap = new WeakHashMap();
  10. static Map map = new HashMap();
  11. public static void init(){
  12. String ref1= new String("obejct1");
  13. String ref2 = new String("obejct2");
  14. String ref3 = new String ("obejct3");
  15. String ref4 = new String ("obejct4");
  16. wMap.put(ref1, "chaheObject1");
  17. wMap.put(ref2, "chaheObject2");
  18. map.put(ref3, "chaheObject3");
  19. map.put(ref4, "chaheObject4");
  20. System.out.println("String引用ref1,ref2,ref3,ref4 消失");
  21. }
  22. public static void testWeakHashMap(){
  23. System.out.println("WeakHashMap GC之前");
  24. for (Object o : wMap.entrySet()) {
  25. System.out.println(o);
  26. }
  27. try {
  28. System.gc();
  29. TimeUnit.SECONDS.sleep(20);
  30. } catch (InterruptedException e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. System.out.println("WeakHashMap GC之后");
  35. for (Object o : wMap.entrySet()) {
  36. System.out.println(o);
  37. }
  38. }
  39. public static void testHashMap(){
  40. System.out.println("HashMap GC之前");
  41. for (Object o : map.entrySet()) {
  42. System.out.println(o);
  43. }
  44. try {
  45. System.gc();
  46. TimeUnit.SECONDS.sleep(20);
  47. } catch (InterruptedException e) {
  48. // TODO Auto-generated catch block
  49. e.printStackTrace();
  50. }
  51. System.out.println("HashMap GC之后");
  52. for (Object o : map.entrySet()) {
  53. System.out.println(o);
  54. }
  55. }
  56. public static void main(String[] args) {
  57. init();
  58. testWeakHashMap();
  59. testHashMap();
  60. }
  61. }
  62. /** 结果
  63. String引用ref1,ref2,ref3,ref4 消失
  64. WeakHashMap GC之前
  65. obejct2=chaheObject2
  66. obejct1=chaheObject1
  67. WeakHashMap GC之后
  68. HashMap GC之前
  69. obejct4=chaheObject4
  70. obejct3=chaheObject3
  71. Disconnected from the target VM, address: '127.0.0.1:51628', transport: 'socket'
  72. HashMap GC之后
  73. obejct4=chaheObject4
  74. obejct3=chaheObject3
  75. **/



上面代码和图示主演演示WeakHashMap如何自动释放缓存对象,当init函数执行完成后,局部变量字符串引用weakd1,weakd2,d1,d2都会消失,此时只有静态map中保存中对字符串对象的引用,可以看到,调用gc之后,hashmap的没有被回收,而WeakHashmap里面的缓存被回收了。

监听器和回调

内存泄漏第三个常见来源是监听器和其他回调,如果客户端在你实现的API中注册回调,却没有显示的取消,那么就会积聚。需要确保回调立即被当作垃圾回收的最佳方法是只保存他的若引用,例如将他们保存成为WeakHashMap中的键。

java程序员--小心你代码中的内存泄漏的更多相关文章

  1. Java程序员如何在竞争中保持优势

    Java程序员入门容易,进阶很难,想要在竞争中保持优势,脚踏实地的同时也要仰望星空规划自己的未来.时间在流逝,年龄在增加,你期望的薪水也在不断增多,你总得让自己能力持续增加以配得上想要的收入吧. 从初 ...

  2. java程序员图文并茂细说Unity中调用Android的接口

    http://bbs.csdn.net/topics/391876421 最近做一个项目,为同事提供接口,能使他在Unity中调用Android中的函数来实现QQ登陆并获取用户信息.按照一些书上和一些 ...

  3. 2017年 Java 程序员,风光背后的危机

    不得不承认,经历过行业的飞速发展期,互联网的整体发展趋于平稳.为什么这么说?为什么要放在 Java 程序员的盘点下说? 的确,对于进可攻前端,后可守后端大本营的 Java 程序员而言,虽然供应逐年上涨 ...

  4. 【Python】Java程序员学习Python(二)— 开发环境搭建

    巧妇难为无米之炊,我最爱的还是鸡蛋羹,因为我和鸡蛋羹有段不能说的秘密. 不管学啥,都要有环境,对于程序员来说搭建个开发环境应该不是什么难题.按顺序一步步来就可以,我也只是记录我的安装过程,你也可以滴. ...

  5. Android java程序员必备技能,集合与数组中遍历元素,增强for循环的使用详解及代码

    Android java程序员必备技能,集合与数组中遍历元素, 增强for循环的使用详解及代码 作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 For ...

  6. Java中基本数据类型的存储方式和相关内存的处理方式(java程序员必读经典)

    1.java是如何管理内存的 java的内存管理就是对象的分配和释放问题.(其中包括两部分) 分配:内存的分配是由程序完成的,程序员需要通过关键字new为每个对象申请内存空间(基本类型除外),所有的对 ...

  7. 一个10年Java程序员的年终总结,献给还在迷茫中的你

    我越来越担心我作为一个Java程序员的未来. 恍然间,发现自己在这个行业里已经摸爬滚打将近10年了,原以为自己就凭已有的项目经验和工作经历怎么着也应该算得上是一个业内比较资历的人士了,但是今年在换工作 ...

  8. 十年京东Java程序员的工作总结,写给迷茫中的你!

    很多年前,刚刚从大学毕业的时候,很多公司来校招.其中最烂俗的一个面试问题是:“你希望你之后三到五年的发展是什么?”.我当时的标准回答是(原话):“成为在某一方面能够独当一面的技术专家“.后来经历了几家 ...

  9. 作为一名双非本科毕业的Java程序员,我该如何在日益严重的内卷化中避免被裁?

    前言 对一个 Java 程序员而言,并发编程能否熟练掌握是判断他是不是优秀的重要标准之一.因为并发编程在 Java 语言中最为晦涩的知识点,它涉及内存.CPU.操作系统.编程语言等多方面的基础能力,更 ...

随机推荐

  1. ECSHOP session

    ECSHOP session传值 <?phpclass cls_session{    var $session_table  = ''; ; // SESSION 过期时间 var $sess ...

  2. checkbox、radio控件和文字不对其

    一般使用html控件的时候  单选按钮和复选框的控件和文字不对齐 给input控件加上   style="vertical-align: middle; margin-top: -2px; ...

  3. spark连接mongodb

    1.添加依赖 hadoop和mongodb的连接器 <dependency> <groupId>org.mongodb.mongo-hadoop</groupId> ...

  4. iOS 之 Block Variable

    在某个变量前面加__block  ,这个变量就变成了block variable.那么就可以在block里面修改该值.

  5. angular2教程

    https://github.com/lewis617/angular2-tutorial

  6. 负载均衡 Lvs nat 模式笔记

    nat技术(网络地址转换) 缺点就是进入和返回都通过调度器的服务器,未来可能会成为瓶颈 实验:nat 模式 先在调度器安装ipvsadm 后再添加网卡,后面就连不上网了(yum -y install ...

  7. 转对象(含length属性)成数组Array.prototype.slice.call(arguments)

    我们知道,Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组,除了IE下的节点集合(因为ie下的dom对象是以com对象的形式实现的,js ...

  8. win7如何安装mircosoft SDKs

    WIN7不能安装SDK 7.1是因为系统程序里含Microsoft .NET Framework 4 Extended和Microsoft .NET Framework 4 Client Profil ...

  9. 求求别再这么用log4x了

    sl4j或者log4j中,推荐的记录方式是: private Logger log = Logger.getLogger(getClass()); //或者 private static final ...

  10. 一篇完整的FlexBox布局指南

    一篇完整的FlexBox布局指南 转载请标注本文链接并附带以下信息: 译:Cydiacen 作者:CHRIS COYIER 原文:A Complete Guide to Flexbox 原文更新于 2 ...